DO NOT MERGE Restore libcorkscrew unwinding. automerge: 5a69c1d  -s ours
automerge: d7c8db1  -s ours

* commit 'd7c8db124c1b4b13d7f55f7c338913ec6d0cd3d1':
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 0254bd2..e78fc88 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -53,3 +53,4 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/bin/reboot)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/root/default.prop)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/recovery/root/default.prop)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/lmkd_intermediates/import_includes)
diff --git a/adb/Android.mk b/adb/Android.mk
index 50e28a6..af7d7e5 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -39,13 +39,11 @@
   ifneq ($(strip $(USE_CYGWIN)),)
     # Pure cygwin case
     LOCAL_LDLIBS += -lpthread -lgdi32
-    LOCAL_C_INCLUDES += /usr/include/w32api/ddk
   endif
   ifneq ($(strip $(USE_MINGW)),)
     # MinGW under Linux case
     LOCAL_LDLIBS += -lws2_32 -lgdi32
     USE_SYSDEPS_WIN32 := 1
-    LOCAL_C_INCLUDES += /usr/i586-mingw32msvc/include/ddk
   endif
   LOCAL_C_INCLUDES += development/host/windows/usb/api/
 endif
@@ -102,7 +100,6 @@
 
 LOCAL_SRC_FILES := \
 	adb.c \
-	backup_service.c \
 	fdevent.c \
 	transport.c \
 	transport_local.c \
@@ -168,7 +165,7 @@
 
 LOCAL_MODULE := adb
 
-LOCAL_STATIC_LIBRARIES := libzipfile libunz libcutils
+LOCAL_STATIC_LIBRARIES := libzipfile libunz libcutils liblog
 
 LOCAL_SHARED_LIBRARIES := libcrypto
 
diff --git a/adb/adb.c b/adb/adb.c
index 90bdbaa..10a1e0d 100644
--- a/adb/adb.c
+++ b/adb/adb.c
@@ -37,8 +37,8 @@
 #include <cutils/properties.h>
 #include <private/android_filesystem_config.h>
 #include <sys/capability.h>
-#include <linux/prctl.h>
 #include <sys/mount.h>
+#include <sys/prctl.h>
 #include <getopt.h>
 #include <selinux/selinux.h>
 #else
@@ -1670,11 +1670,6 @@
         /* we don't even need to send a reply */
         return 0;
     }
-#endif // ADB_HOST
-
-    int ret = handle_forward_request(service, ttype, serial, reply_fd);
-    if (ret >= 0)
-      return ret - 1;
 
     if(!strncmp(service,"get-state",strlen("get-state"))) {
         transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
@@ -1682,6 +1677,11 @@
         send_msg_with_okay(reply_fd, state, strlen(state));
         return 0;
     }
+#endif // ADB_HOST
+
+    int ret = handle_forward_request(service, ttype, serial, reply_fd);
+    if (ret >= 0)
+      return ret - 1;
     return -1;
 }
 
diff --git a/adb/adb.h b/adb/adb.h
index 2504f99..4f06800 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -19,6 +19,7 @@
 
 #include <limits.h>
 
+#include "adb_trace.h"
 #include "transport.h"  /* readx(), writex() */
 
 #define MAX_PAYLOAD 4096
@@ -36,7 +37,7 @@
 #define ADB_VERSION_MAJOR 1         // Used for help/version information
 #define ADB_VERSION_MINOR 0         // Used for help/version information
 
-#define ADB_SERVER_VERSION    31    // Increment this when we want to force users to start a new adb server
+#define ADB_SERVER_VERSION    32    // Increment this when we want to force users to start a new adb server
 
 typedef struct amessage amessage;
 typedef struct apacket apacket;
@@ -326,11 +327,6 @@
 int handle_forward_request(const char* service, transport_type ttype, char* serial, int reply_fd);
 
 #if !ADB_HOST
-typedef enum {
-    BACKUP,
-    RESTORE
-} BackupOperation;
-int backup_service(BackupOperation operation, char* args);
 void framebuffer_service(int fd, void *cookie);
 void remount_service(int fd, void *cookie);
 #endif
@@ -342,85 +338,6 @@
 int check_header(apacket *p);
 int check_data(apacket *p);
 
-/* define ADB_TRACE to 1 to enable tracing support, or 0 to disable it */
-
-#define  ADB_TRACE    1
-
-/* IMPORTANT: if you change the following list, don't
- * forget to update the corresponding 'tags' table in
- * the adb_trace_init() function implemented in adb.c
- */
-typedef enum {
-    TRACE_ADB = 0,   /* 0x001 */
-    TRACE_SOCKETS,
-    TRACE_PACKETS,
-    TRACE_TRANSPORT,
-    TRACE_RWX,       /* 0x010 */
-    TRACE_USB,
-    TRACE_SYNC,
-    TRACE_SYSDEPS,
-    TRACE_JDWP,      /* 0x100 */
-    TRACE_SERVICES,
-    TRACE_AUTH,
-} AdbTrace;
-
-#if ADB_TRACE
-
-#if !ADB_HOST
-/*
- * When running inside the emulator, guest's adbd can connect to 'adb-debug'
- * qemud service that can display adb trace messages (on condition that emulator
- * has been started with '-debug adb' option).
- */
-
-/* Delivers a trace message to the emulator via QEMU pipe. */
-void adb_qemu_trace(const char* fmt, ...);
-/* Macro to use to send ADB trace messages to the emulator. */
-#define DQ(...)    adb_qemu_trace(__VA_ARGS__)
-#else
-#define DQ(...) ((void)0)
-#endif  /* !ADB_HOST */
-
-  extern int     adb_trace_mask;
-  extern unsigned char    adb_trace_output_count;
-  void    adb_trace_init(void);
-
-#  define ADB_TRACING  ((adb_trace_mask & (1 << TRACE_TAG)) != 0)
-
-  /* you must define TRACE_TAG before using this macro */
-#  define  D(...)                                      \
-        do {                                           \
-            if (ADB_TRACING) {                         \
-                int save_errno = errno;                \
-                adb_mutex_lock(&D_lock);               \
-                fprintf(stderr, "%s::%s():",           \
-                        __FILE__, __FUNCTION__);       \
-                errno = save_errno;                    \
-                fprintf(stderr, __VA_ARGS__ );         \
-                fflush(stderr);                        \
-                adb_mutex_unlock(&D_lock);             \
-                errno = save_errno;                    \
-           }                                           \
-        } while (0)
-#  define  DR(...)                                     \
-        do {                                           \
-            if (ADB_TRACING) {                         \
-                int save_errno = errno;                \
-                adb_mutex_lock(&D_lock);               \
-                errno = save_errno;                    \
-                fprintf(stderr, __VA_ARGS__ );         \
-                fflush(stderr);                        \
-                adb_mutex_unlock(&D_lock);             \
-                errno = save_errno;                    \
-           }                                           \
-        } while (0)
-#else
-#  define  D(...)          ((void)0)
-#  define  DR(...)         ((void)0)
-#  define  ADB_TRACING     0
-#endif
-
-
 #if !DEBUG_PACKETS
 #define print_packet(tag,p) do {} while (0)
 #endif
@@ -476,6 +393,11 @@
 extern int HOST;
 extern int SHELL_EXIT_NOTIFY_FD;
 
+typedef enum {
+    SUBPROC_PTY = 0,
+    SUBPROC_RAW = 1,
+} subproc_mode;
+
 #define CHUNK_SIZE (64*1024)
 
 #if !ADB_HOST
diff --git a/adb/adb_auth_client.c b/adb/adb_auth_client.c
index f8d7306..55e9dca 100644
--- a/adb/adb_auth_client.c
+++ b/adb/adb_auth_client.c
@@ -57,7 +57,7 @@
     char *sep;
     int ret;
 
-    f = fopen(file, "r");
+    f = fopen(file, "re");
     if (!f) {
         D("Can't open '%s'\n", file);
         return;
@@ -126,7 +126,7 @@
     FILE *f;
     int ret;
 
-    f = fopen("/dev/urandom", "r");
+    f = fopen("/dev/urandom", "re");
     if (!f)
         return 0;
 
@@ -175,7 +175,7 @@
 
     if (events & FDE_READ) {
         ret = unix_read(fd, response, sizeof(response));
-        if (ret < 0) {
+        if (ret <= 0) {
             D("Framework disconnect\n");
             if (usb_transport)
                 fdevent_remove(&usb_transport->auth_fde);
@@ -257,6 +257,7 @@
         D("Failed to get adbd socket\n");
         return;
     }
+    fcntl(fd, F_SETFD, FD_CLOEXEC);
 
     ret = listen(fd, 4);
     if (ret < 0) {
diff --git a/adb/adb_client.c b/adb/adb_client.c
index 1e47486..eb1720d 100644
--- a/adb/adb_client.c
+++ b/adb/adb_client.c
@@ -279,7 +279,7 @@
 
     fd = _adb_connect(service);
     if(fd == -1) {
-        fprintf(stderr,"error: %s\n", __adb_error);
+        D("_adb_connect error: %s\n", __adb_error);
     } else if(fd == -2) {
         fprintf(stderr,"** daemon still not running\n");
     }
@@ -296,6 +296,7 @@
 {
     int fd = adb_connect(service);
     if(fd < 0) {
+        fprintf(stderr, "error: %s\n", adb_error());
         return -1;
     }
 
diff --git a/adb/adb_trace.h b/adb/adb_trace.h
new file mode 100644
index 0000000..8a5d9f8
--- /dev/null
+++ b/adb/adb_trace.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2014 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 __ADB_TRACE_H
+#define __ADB_TRACE_H
+
+#if !ADB_HOST
+#include <android/log.h>
+#endif
+
+/* define ADB_TRACE to 1 to enable tracing support, or 0 to disable it */
+#define  ADB_TRACE    1
+
+/* IMPORTANT: if you change the following list, don't
+ * forget to update the corresponding 'tags' table in
+ * the adb_trace_init() function implemented in adb.c
+ */
+typedef enum {
+    TRACE_ADB = 0,   /* 0x001 */
+    TRACE_SOCKETS,
+    TRACE_PACKETS,
+    TRACE_TRANSPORT,
+    TRACE_RWX,       /* 0x010 */
+    TRACE_USB,
+    TRACE_SYNC,
+    TRACE_SYSDEPS,
+    TRACE_JDWP,      /* 0x100 */
+    TRACE_SERVICES,
+    TRACE_AUTH,
+    TRACE_FDEVENT,
+} AdbTrace;
+
+#if ADB_TRACE
+
+#if !ADB_HOST
+/*
+ * When running inside the emulator, guest's adbd can connect to 'adb-debug'
+ * qemud service that can display adb trace messages (on condition that emulator
+ * has been started with '-debug adb' option).
+ */
+
+/* Delivers a trace message to the emulator via QEMU pipe. */
+void adb_qemu_trace(const char* fmt, ...);
+/* Macro to use to send ADB trace messages to the emulator. */
+#define DQ(...)    adb_qemu_trace(__VA_ARGS__)
+#else
+#define DQ(...) ((void)0)
+#endif  /* !ADB_HOST */
+
+extern int     adb_trace_mask;
+extern unsigned char    adb_trace_output_count;
+void    adb_trace_init(void);
+
+#  define ADB_TRACING  ((adb_trace_mask & (1 << TRACE_TAG)) != 0)
+
+/* you must define TRACE_TAG before using this macro */
+#if ADB_HOST
+#  define  D(...)                                      \
+        do {                                           \
+            if (ADB_TRACING) {                         \
+                int save_errno = errno;                \
+                adb_mutex_lock(&D_lock);               \
+                fprintf(stderr, "%s::%s():",           \
+                        __FILE__, __FUNCTION__);       \
+                errno = save_errno;                    \
+                fprintf(stderr, __VA_ARGS__ );         \
+                fflush(stderr);                        \
+                adb_mutex_unlock(&D_lock);             \
+                errno = save_errno;                    \
+           }                                           \
+        } while (0)
+#  define  DR(...)                                     \
+        do {                                           \
+            if (ADB_TRACING) {                         \
+                int save_errno = errno;                \
+                adb_mutex_lock(&D_lock);               \
+                errno = save_errno;                    \
+                fprintf(stderr, __VA_ARGS__ );         \
+                fflush(stderr);                        \
+                adb_mutex_unlock(&D_lock);             \
+                errno = save_errno;                    \
+           }                                           \
+        } while (0)
+#  define  DD(...)                                     \
+        do {                                           \
+          int save_errno = errno;                      \
+          adb_mutex_lock(&D_lock);                     \
+          fprintf(stderr, "%s::%s():",                 \
+                  __FILE__, __FUNCTION__);             \
+          errno = save_errno;                          \
+          fprintf(stderr, __VA_ARGS__ );               \
+          fflush(stderr);                              \
+          adb_mutex_unlock(&D_lock);                   \
+          errno = save_errno;                          \
+        } while (0)
+#else
+#  define  D(...)                                      \
+        do {                                           \
+            if (ADB_TRACING) {                         \
+                __android_log_print(                   \
+                    ANDROID_LOG_INFO,                  \
+                    __FUNCTION__,                      \
+                    __VA_ARGS__ );                     \
+            }                                          \
+        } while (0)
+#  define  DR(...)                                     \
+        do {                                           \
+            if (ADB_TRACING) {                         \
+                __android_log_print(                   \
+                    ANDROID_LOG_INFO,                  \
+                    __FUNCTION__,                      \
+                    __VA_ARGS__ );                     \
+            }                                          \
+        } while (0)
+#  define  DD(...)                                     \
+        do {                                           \
+          __android_log_print(                         \
+              ANDROID_LOG_INFO,                        \
+              __FUNCTION__,                            \
+              __VA_ARGS__ );                           \
+        } while (0)
+#endif /* ADB_HOST */
+#else
+#  define  D(...)          ((void)0)
+#  define  DR(...)         ((void)0)
+#  define  DD(...)         ((void)0)
+#  define  ADB_TRACING     0
+#endif /* ADB_TRACE */
+
+#endif /* __ADB_TRACE_H */
diff --git a/adb/backup_service.c b/adb/backup_service.c
deleted file mode 100644
index 654e0f3..0000000
--- a/adb/backup_service.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2011 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 <unistd.h>
-#include <stdio.h>
-
-#include "sysdeps.h"
-
-#define TRACE_TAG  TRACE_ADB
-#include "adb.h"
-
-typedef struct {
-    pid_t pid;
-    int fd;
-} backup_harvest_params;
-
-// socketpair but do *not* mark as close_on_exec
-static int backup_socketpair(int sv[2]) {
-    int rc = unix_socketpair( AF_UNIX, SOCK_STREAM, 0, sv );
-    if (rc < 0)
-        return -1;
-
-    return 0;
-}
-
-// harvest the child process then close the read end of the socketpair
-static void* backup_child_waiter(void* args) {
-    int status;
-    backup_harvest_params* params = (backup_harvest_params*) args;
-
-    waitpid(params->pid, &status, 0);
-    adb_close(params->fd);
-    free(params);
-    return NULL;
-}
-
-/* returns the data socket passing the backup data here for forwarding */
-int backup_service(BackupOperation op, char* args) {
-    pid_t pid;
-    int s[2];
-    char* operation;
-
-    // Command string depends on our invocation
-    if (op == BACKUP) {
-        operation = "backup";
-    } else {
-        operation = "restore";
-    }
-
-    D("backup_service(%s, %s)\n", operation, args);
-
-    // set up the pipe from the subprocess to here
-    // parent will read s[0]; child will write s[1]
-    if (backup_socketpair(s)) {
-        D("can't create backup/restore socketpair\n");
-        fprintf(stderr, "unable to create backup/restore socketpair\n");
-        return -1;
-    }
-
-    D("Backup/restore socket pair: (send=%d, receive=%d)\n", s[1], s[0]);
-    close_on_exec(s[0]);    // only the side we hold on to
-
-    // spin off the child process to run the backup command
-    pid = fork();
-    if (pid < 0) {
-        // failure
-        D("can't fork for %s\n", operation);
-        fprintf(stderr, "unable to fork for %s\n", operation);
-        adb_close(s[0]);
-        adb_close(s[1]);
-        return -1;
-    }
-
-    // Great, we're off and running.
-    if (pid == 0) {
-        // child -- actually run the backup here
-        char* p;
-        int argc;
-        char portnum[16];
-        char** bu_args;
-
-        // fixed args:  [0] is 'bu', [1] is the port number, [2] is the 'operation' string
-        argc = 3;
-        for (p = (char*)args; p && *p; ) {
-            argc++;
-            while (*p && *p != ':') p++;
-            if (*p == ':') p++;
-        }
-
-        bu_args = (char**) alloca(argc*sizeof(char*) + 1);
-
-        // run through again to build the argv array
-        argc = 0;
-        bu_args[argc++] = "bu";
-        snprintf(portnum, sizeof(portnum), "%d", s[1]);
-        bu_args[argc++] = portnum;
-        bu_args[argc++] = operation;
-        for (p = (char*)args; p && *p; ) {
-            bu_args[argc++] = p;
-            while (*p && *p != ':') p++;
-            if (*p == ':') {
-                *p = 0;
-                p++;
-            }
-        }
-        bu_args[argc] = NULL;
-
-        // Close the half of the socket that we don't care about, route 'bu's console
-        // to the output socket, and off we go
-        adb_close(s[0]);
-
-        // off we go
-        execvp("/system/bin/bu", (char * const *)bu_args);
-        // oops error - close up shop and go home
-        fprintf(stderr, "Unable to exec 'bu', bailing\n");
-        exit(-1);
-    } else {
-        adb_thread_t t;
-        backup_harvest_params* params;
-
-        // parent, i.e. adbd -- close the sending half of the socket
-        D("fork() returned pid %d\n", pid);
-        adb_close(s[1]);
-
-        // spin a thread to harvest the child process
-        params = (backup_harvest_params*) malloc(sizeof(backup_harvest_params));
-        params->pid = pid;
-        params->fd = s[0];
-        if (adb_thread_create(&t, backup_child_waiter, params)) {
-            adb_close(s[0]);
-            free(params);
-            D("Unable to create child harvester\n");
-            return -1;
-        }
-    }
-
-    // we'll be reading from s[0] as the data is sent by the child process
-    return s[0];
-}
diff --git a/adb/commandline.c b/adb/commandline.c
index 2e4cd37..05b4ef6 100644
--- a/adb/commandline.c
+++ b/adb/commandline.c
@@ -15,6 +15,7 @@
  */
 
 #include <stdio.h>
+#include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
@@ -41,8 +42,9 @@
 
 void get_my_path(char *s, size_t maxLen);
 int find_sync_dirs(const char *srcarg,
-        char **android_srcdir_out, char **data_srcdir_out);
+        char **android_srcdir_out, char **data_srcdir_out, char **vendor_srcdir_out);
 int install_app(transport_type transport, char* serial, int argc, char** argv);
+int install_multiple_app(transport_type transport, char* serial, int argc, char** argv);
 int uninstall_app(transport_type transport, char* serial, int argc, char** argv);
 
 static const char *gProductOutPath = NULL;
@@ -110,9 +112,10 @@
         "  adb push [-p] <local> <remote>\n"
         "                               - copy file/dir to device\n"
         "                                 ('-p' to display the transfer progress)\n"
-        "  adb pull [-p] <remote> [<local>]\n"
+        "  adb pull [-p] [-a] <remote> [<local>]\n"
         "                               - copy file/dir from device\n"
         "                                 ('-p' to display the transfer progress)\n"
+        "                                 ('-a' means copy timestamp and mode)\n"
         "  adb sync [ <directory> ]     - copy host->device only if changed\n"
         "                                 (-l means list but don't copy)\n"
         "                                 (see 'adb help all')\n"
@@ -150,13 +153,15 @@
         "                               - remove a specific reversed socket connection\n"
         "  adb reverse --remove-all     - remove all reversed socket connections from device\n"
         "  adb jdwp                     - list PIDs of processes hosting a JDWP transport\n"
-        "  adb install [-l] [-r] [-d] [-s] [--algo <algorithm name> --key <hex-encoded key> --iv <hex-encoded iv>] <file>\n"
+        "  adb install [-lrtsd] <file>\n"
+        "  adb install-multiple [-lrtsdp] <file...>\n"
         "                               - push this package file to the device and install it\n"
-        "                                 ('-l' means forward-lock the app)\n"
-        "                                 ('-r' means reinstall the app, keeping its data)\n"
-        "                                 ('-d' means allow version code downgrade)\n"
-        "                                 ('-s' means install on SD card instead of internal storage)\n"
-        "                                 ('--algo', '--key', and '--iv' mean the file is encrypted already)\n"
+        "                                 (-l: forward lock application)\n"
+        "                                 (-r: replace existing application)\n"
+        "                                 (-t: allow test packages)\n"
+        "                                 (-s: install application on sdcard)\n"
+        "                                 (-d: allow version code downgrade)\n"
+        "                                 (-p: partial application install)\n"
         "  adb uninstall [-k] <package> - remove this app package from the device\n"
         "                                 ('-k' means keep the data and cache directories)\n"
         "  adb bugreport                - return all information from the device\n"
@@ -195,7 +200,7 @@
         "  adb get-serialno             - prints: <serial-number>\n"
         "  adb get-devpath              - prints: <device-path>\n"
         "  adb status-window            - continuously print device status for a specified device\n"
-        "  adb remount                  - remounts the /system partition on the device read-write\n"
+        "  adb remount                  - remounts the /system and /vendor (if present) partitions on the device read-write\n"
         "  adb reboot [bootloader|recovery] - reboots the device, optionally into the bootloader or recovery program\n"
         "  adb reboot-bootloader        - reboots the device into the bootloader\n"
         "  adb root                     - restarts the adbd daemon with root permissions\n"
@@ -211,9 +216,9 @@
         "adb sync notes: adb sync [ <directory> ]\n"
         "  <localdir> can be interpreted in several ways:\n"
         "\n"
-        "  - If <directory> is not specified, both /system and /data partitions will be updated.\n"
+        "  - If <directory> is not specified, /system, /vendor (if present), and /data partitions will be updated.\n"
         "\n"
-        "  - If it is \"system\" or \"data\", only the corresponding partition\n"
+        "  - If it is \"system\", \"vendor\" or \"data\", only the corresponding partition\n"
         "    is updated.\n"
         "\n"
         "environmental variables:\n"
@@ -279,6 +284,24 @@
     }
 }
 
+static void read_status_line(int fd, char* buf, size_t count)
+{
+    count--;
+    while (count > 0) {
+        int len = adb_read(fd, buf, count);
+        if (len == 0) {
+            break;
+        } else if (len < 0) {
+            if (errno == EINTR) continue;
+            break;
+        }
+
+        buf += len;
+        count -= len;
+    }
+    *buf = '\0';
+}
+
 static void copy_to_file(int inFd, int outFd) {
     const size_t BUFSIZE = 32 * 1024;
     char* buf = (char*) malloc(BUFSIZE);
@@ -286,8 +309,17 @@
     long total = 0;
 
     D("copy_to_file(%d -> %d)\n", inFd, outFd);
+#ifdef HAVE_TERMIO_H
+    if (inFd == STDIN_FILENO) {
+        stdin_raw_init(STDIN_FILENO);
+    }
+#endif
     for (;;) {
-        len = adb_read(inFd, buf, BUFSIZE);
+        if (inFd == STDIN_FILENO) {
+            len = unix_read(inFd, buf, BUFSIZE);
+        } else {
+            len = adb_read(inFd, buf, BUFSIZE);
+        }
         if (len == 0) {
             D("copy_to_file() : read 0 bytes; exiting\n");
             break;
@@ -300,9 +332,19 @@
             D("copy_to_file() : error %d\n", errno);
             break;
         }
-        adb_write(outFd, buf, len);
+        if (outFd == STDOUT_FILENO) {
+            fwrite(buf, 1, len, stdout);
+            fflush(stdout);
+        } else {
+            adb_write(outFd, buf, len);
+        }
         total += len;
     }
+#ifdef HAVE_TERMIO_H
+    if (inFd == STDIN_FILENO) {
+        stdin_raw_restore(STDIN_FILENO);
+    }
+#endif
     D("copy_to_file() finished after %lu bytes\n", total);
     free(buf);
 }
@@ -481,6 +523,115 @@
     return status;
 }
 
+#define SIDELOAD_HOST_BLOCK_SIZE (CHUNK_SIZE)
+
+/*
+ * The sideload-host protocol serves the data in a file (given on the
+ * command line) to the client, using a simple protocol:
+ *
+ * - The connect message includes the total number of bytes in the
+ *   file and a block size chosen by us.
+ *
+ * - The other side sends the desired block number as eight decimal
+ *   digits (eg "00000023" for block 23).  Blocks are numbered from
+ *   zero.
+ *
+ * - We send back the data of the requested block.  The last block is
+ *   likely to be partial; when the last block is requested we only
+ *   send the part of the block that exists, it's not padded up to the
+ *   block size.
+ *
+ * - When the other side sends "DONEDONE" instead of a block number,
+ *   we hang up.
+ */
+int adb_sideload_host(const char* fn) {
+    uint8_t* data;
+    unsigned sz;
+    size_t xfer = 0;
+    int status;
+
+    printf("loading: '%s'", fn);
+    fflush(stdout);
+    data = load_file(fn, &sz);
+    if (data == 0) {
+        printf("\n");
+        fprintf(stderr, "* cannot read '%s' *\n", fn);
+        return -1;
+    }
+
+    char buf[100];
+    sprintf(buf, "sideload-host:%d:%d", sz, SIDELOAD_HOST_BLOCK_SIZE);
+    int fd = adb_connect(buf);
+    if (fd < 0) {
+        // Try falling back to the older sideload method.  Maybe this
+        // is an older device that doesn't support sideload-host.
+        printf("\n");
+        status = adb_download_buffer("sideload", fn, data, sz, 1);
+        goto done;
+    }
+
+    int opt = SIDELOAD_HOST_BLOCK_SIZE;
+    opt = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const void *) &opt, sizeof(opt));
+
+    int last_percent = -1;
+    for (;;) {
+        if (readx(fd, buf, 8)) {
+            fprintf(stderr, "* failed to read command: %s\n", adb_error());
+            status = -1;
+            goto done;
+        }
+
+        if (strncmp("DONEDONE", buf, 8) == 0) {
+            status = 0;
+            break;
+        }
+
+        buf[8] = '\0';
+        int block = strtol(buf, NULL, 10);
+
+        size_t offset = block * SIDELOAD_HOST_BLOCK_SIZE;
+        if (offset >= sz) {
+            fprintf(stderr, "* attempt to read past end: %s\n", adb_error());
+            status = -1;
+            goto done;
+        }
+        uint8_t* start = data + offset;
+        size_t offset_end = offset + SIDELOAD_HOST_BLOCK_SIZE;
+        size_t to_write = SIDELOAD_HOST_BLOCK_SIZE;
+        if (offset_end > sz) {
+            to_write = sz - offset;
+        }
+
+        if(writex(fd, start, to_write)) {
+            adb_status(fd);
+            fprintf(stderr,"* failed to write data '%s' *\n", adb_error());
+            status = -1;
+            goto done;
+        }
+        xfer += to_write;
+
+        // For normal OTA packages, we expect to transfer every byte
+        // twice, plus a bit of overhead (one read during
+        // verification, one read of each byte for installation, plus
+        // extra access to things like the zip central directory).
+        // This estimate of the completion becomes 100% when we've
+        // transferred ~2.13 (=100/47) times the package size.
+        int percent = (int)(xfer * 47LL / (sz ? sz : 1));
+        if (percent != last_percent) {
+            printf("\rserving: '%s'  (~%d%%)    ", fn, percent);
+            fflush(stdout);
+            last_percent = percent;
+        }
+    }
+
+    printf("\rTotal xfer: %.2fx%*s\n", (double)xfer / (sz ? sz : 1), (int)strlen(fn)+10, "");
+
+  done:
+    if (fd >= 0) adb_close(fd);
+    free(data);
+    return status;
+}
+
 static void status_window(transport_type ttype, const char* serial)
 {
     char command[4096];
@@ -525,39 +676,45 @@
     }
 }
 
-/** duplicate string and quote all \ " ( ) chars + space character. */
-static char *
-dupAndQuote(const char *s)
+static int should_escape(const char c)
+{
+    return (c == ' ' || c == '\'' || c == '"' || c == '\\' || c == '(' || c == ')');
+}
+
+/* Duplicate and escape given argument. */
+static char *escape_arg(const char *s)
 {
     const char *ts;
     size_t alloc_len;
     char *ret;
     char *dest;
 
-    ts = s;
-
     alloc_len = 0;
-
-    for( ;*ts != '\0'; ts++) {
+    for (ts = s; *ts != '\0'; ts++) {
         alloc_len++;
-        if (*ts == ' ' || *ts == '"' || *ts == '\\' || *ts == '(' || *ts == ')') {
+        if (should_escape(*ts)) {
             alloc_len++;
         }
     }
 
-    ret = (char *)malloc(alloc_len + 1);
-
-    ts = s;
-    dest = ret;
-
-    for ( ;*ts != '\0'; ts++) {
-        if (*ts == ' ' || *ts == '"' || *ts == '\\' || *ts == '(' || *ts == ')') {
-            *dest++ = '\\';
-        }
-
-        *dest++ = *ts;
+    if (alloc_len == 0) {
+        // Preserve empty arguments
+        ret = (char *) malloc(3);
+        ret[0] = '\"';
+        ret[1] = '\"';
+        ret[2] = '\0';
+        return ret;
     }
 
+    ret = (char *) malloc(alloc_len + 1);
+    dest = ret;
+
+    for (ts = s; *ts != '\0'; ts++) {
+        if (should_escape(*ts)) {
+            *dest++ = '\\';
+        }
+        *dest++ = *ts;
+    }
     *dest++ = '\0';
 
     return ret;
@@ -664,30 +821,24 @@
     char buf[4096];
 
     char *log_tags;
-    char *quoted_log_tags;
+    char *quoted;
 
     log_tags = getenv("ANDROID_LOG_TAGS");
-    quoted_log_tags = dupAndQuote(log_tags == NULL ? "" : log_tags);
-
+    quoted = escape_arg(log_tags == NULL ? "" : log_tags);
     snprintf(buf, sizeof(buf),
-        "shell:export ANDROID_LOG_TAGS=\"\%s\" ; exec logcat",
-        quoted_log_tags);
+            "shell:export ANDROID_LOG_TAGS=\"%s\"; exec logcat", quoted);
+    free(quoted);
 
-    free(quoted_log_tags);
-
-    if (!strcmp(argv[0],"longcat")) {
-        strncat(buf, " -v long", sizeof(buf)-1);
+    if (!strcmp(argv[0], "longcat")) {
+        strncat(buf, " -v long", sizeof(buf) - 1);
     }
 
     argc -= 1;
     argv += 1;
     while(argc-- > 0) {
-        char *quoted;
-
-        quoted = dupAndQuote (*argv++);
-
-        strncat(buf, " ", sizeof(buf)-1);
-        strncat(buf, quoted, sizeof(buf)-1);
+        quoted = escape_arg(*argv++);
+        strncat(buf, " ", sizeof(buf) - 1);
+        strncat(buf, quoted, sizeof(buf) - 1);
         free(quoted);
     }
 
@@ -939,13 +1090,19 @@
     return path_buf;
 }
 
-
-static void parse_push_pull_args(char** arg, int narg, char const** path1, char const** path2,
-                                 int* show_progress) {
+static void parse_push_pull_args(char **arg, int narg, char const **path1, char const **path2,
+                                 int *show_progress, int *copy_attrs) {
     *show_progress = 0;
+    *copy_attrs = 0;
 
-    if ((narg > 0) && !strcmp(*arg, "-p")) {
-        *show_progress = 1;
+    while (narg > 0) {
+        if (!strcmp(*arg, "-p")) {
+            *show_progress = 1;
+        } else if (!strcmp(*arg, "-a")) {
+            *copy_attrs = 1;
+        } else {
+            break;
+        }
         ++arg;
         --narg;
     }
@@ -969,7 +1126,6 @@
     int is_server = 0;
     int persist = 0;
     int r;
-    int quote;
     transport_type ttype = kTransportAny;
     char* serial = NULL;
     char* server_port_str = NULL;
@@ -1190,19 +1346,14 @@
             return r;
         }
 
-        snprintf(buf, sizeof buf, "shell:%s", argv[1]);
+        snprintf(buf, sizeof(buf), "shell:%s", argv[1]);
         argc -= 2;
         argv += 2;
-        while(argc-- > 0) {
-            strcat(buf, " ");
-
-            /* quote empty strings and strings with spaces */
-            quote = (**argv == 0 || strchr(*argv, ' '));
-            if (quote)
-                strcat(buf, "\"");
-            strcat(buf, *argv++);
-            if (quote)
-                strcat(buf, "\"");
+        while (argc-- > 0) {
+            char *quoted = escape_arg(*argv++);
+            strncat(buf, " ", sizeof(buf) - 1);
+            strncat(buf, quoted, sizeof(buf) - 1);
+            free(quoted);
         }
 
         for(;;) {
@@ -1234,6 +1385,36 @@
         }
     }
 
+    if (!strcmp(argv[0], "exec-in") || !strcmp(argv[0], "exec-out")) {
+        int exec_in = !strcmp(argv[0], "exec-in");
+        int fd;
+
+        snprintf(buf, sizeof buf, "exec:%s", argv[1]);
+        argc -= 2;
+        argv += 2;
+        while (argc-- > 0) {
+            char *quoted = escape_arg(*argv++);
+            strncat(buf, " ", sizeof(buf) - 1);
+            strncat(buf, quoted, sizeof(buf) - 1);
+            free(quoted);
+        }
+
+        fd = adb_connect(buf);
+        if (fd < 0) {
+            fprintf(stderr, "error: %s\n", adb_error());
+            return -1;
+        }
+
+        if (exec_in) {
+            copy_to_file(STDIN_FILENO, fd);
+        } else {
+            copy_to_file(fd, STDOUT_FILENO);
+        }
+
+        adb_close(fd);
+        return 0;
+    }
+
     if(!strcmp(argv[0], "kill-server")) {
         int fd;
         fd = _adb_connect("host:kill");
@@ -1246,7 +1427,7 @@
 
     if(!strcmp(argv[0], "sideload")) {
         if(argc != 2) return usage();
-        if(adb_download("sideload", argv[1], 1)) {
+        if (adb_sideload_host(argv[1])) {
             return 1;
         } else {
             return 0;
@@ -1416,12 +1597,13 @@
 
     if(!strcmp(argv[0], "push")) {
         int show_progress = 0;
+        int copy_attrs = 0; // unused
         const char* lpath = NULL, *rpath = NULL;
 
-        parse_push_pull_args(&argv[1], argc - 1, &lpath, &rpath, &show_progress);
+        parse_push_pull_args(&argv[1], argc - 1, &lpath, &rpath, &show_progress, &copy_attrs);
 
         if ((lpath != NULL) && (rpath != NULL)) {
-            return do_sync_push(lpath, rpath, 0 /* no verify APK */, show_progress);
+            return do_sync_push(lpath, rpath, show_progress);
         }
 
         return usage();
@@ -1429,29 +1611,35 @@
 
     if(!strcmp(argv[0], "pull")) {
         int show_progress = 0;
+        int copy_attrs = 0;
         const char* rpath = NULL, *lpath = ".";
 
-        parse_push_pull_args(&argv[1], argc - 1, &rpath, &lpath, &show_progress);
+        parse_push_pull_args(&argv[1], argc - 1, &rpath, &lpath, &show_progress, &copy_attrs);
 
         if (rpath != NULL) {
-            return do_sync_pull(rpath, lpath, show_progress);
+            return do_sync_pull(rpath, lpath, show_progress, copy_attrs);
         }
 
         return usage();
     }
 
-    if(!strcmp(argv[0], "install")) {
+    if (!strcmp(argv[0], "install")) {
         if (argc < 2) return usage();
         return install_app(ttype, serial, argc, argv);
     }
 
-    if(!strcmp(argv[0], "uninstall")) {
+    if (!strcmp(argv[0], "install-multiple")) {
+        if (argc < 2) return usage();
+        return install_multiple_app(ttype, serial, argc, argv);
+    }
+
+    if (!strcmp(argv[0], "uninstall")) {
         if (argc < 2) return usage();
         return uninstall_app(ttype, serial, argc, argv);
     }
 
     if(!strcmp(argv[0], "sync")) {
-        char *srcarg, *android_srcpath, *data_srcpath;
+        char *srcarg, *android_srcpath, *data_srcpath, *vendor_srcpath;
         int listonly = 0;
 
         int ret;
@@ -1471,15 +1659,18 @@
         } else {
             return usage();
         }
-        ret = find_sync_dirs(srcarg, &android_srcpath, &data_srcpath);
+        ret = find_sync_dirs(srcarg, &android_srcpath, &data_srcpath, &vendor_srcpath);
         if(ret != 0) return usage();
 
         if(android_srcpath != NULL)
             ret = do_sync_sync(android_srcpath, "/system", listonly);
+        if(ret == 0 && vendor_srcpath != NULL)
+            ret = do_sync_sync(vendor_srcpath, "/vendor", listonly);
         if(ret == 0 && data_srcpath != NULL)
             ret = do_sync_sync(data_srcpath, "/data", listonly);
 
         free(android_srcpath);
+        free(vendor_srcpath);
         free(data_srcpath);
         return ret;
     }
@@ -1556,9 +1747,10 @@
     return 1;
 }
 
+#define MAX_ARGV_LENGTH 16
 static int do_cmd(transport_type ttype, char* serial, char *cmd, ...)
 {
-    char *argv[16];
+    char *argv[MAX_ARGV_LENGTH];
     int argc;
     va_list ap;
 
@@ -1575,7 +1767,9 @@
     }
 
     argv[argc++] = cmd;
-    while((argv[argc] = va_arg(ap, char*)) != 0) argc++;
+    while(argc < MAX_ARGV_LENGTH &&
+        (argv[argc] = va_arg(ap, char*)) != 0) argc++;
+    assert(argc < MAX_ARGV_LENGTH);
     va_end(ap);
 
 #if 0
@@ -1590,25 +1784,30 @@
 }
 
 int find_sync_dirs(const char *srcarg,
-        char **android_srcdir_out, char **data_srcdir_out)
+        char **android_srcdir_out, char **data_srcdir_out, char **vendor_srcdir_out)
 {
-    char *android_srcdir, *data_srcdir;
+    char *android_srcdir = NULL, *data_srcdir = NULL, *vendor_srcdir = NULL;
+    struct stat st;
 
     if(srcarg == NULL) {
         android_srcdir = product_file("system");
         data_srcdir = product_file("data");
+        vendor_srcdir = product_file("vendor");
+        /* Check if vendor partition exists */
+        if (lstat(vendor_srcdir, &st) || !S_ISDIR(st.st_mode))
+            vendor_srcdir = NULL;
     } else {
         /* srcarg may be "data", "system" or NULL.
          * if srcarg is NULL, then both data and system are synced
          */
         if(strcmp(srcarg, "system") == 0) {
             android_srcdir = product_file("system");
-            data_srcdir = NULL;
         } else if(strcmp(srcarg, "data") == 0) {
-            android_srcdir = NULL;
             data_srcdir = product_file("data");
+        } else if(strcmp(srcarg, "vendor") == 0) {
+            vendor_srcdir = product_file("vendor");
         } else {
-            /* It's not "system" or "data".
+            /* It's not "system", "vendor", or "data".
              */
             return 1;
         }
@@ -1619,11 +1818,15 @@
     else
         free(android_srcdir);
 
-    if(data_srcdir_out != NULL)
-        *data_srcdir_out = data_srcdir;
+    if(vendor_srcdir_out != NULL)
+        *vendor_srcdir_out = vendor_srcdir;
     else
-        free(data_srcdir);
+        free(vendor_srcdir);
 
+    if(data_srcdir_out != NULL)
+            *data_srcdir_out = data_srcdir;
+        else
+            free(data_srcdir);
     return 0;
 }
 
@@ -1635,12 +1838,9 @@
     snprintf(buf, sizeof(buf), "shell:pm");
 
     while(argc-- > 0) {
-        char *quoted;
-
-        quoted = dupAndQuote(*argv++);
-
-        strncat(buf, " ", sizeof(buf)-1);
-        strncat(buf, quoted, sizeof(buf)-1);
+        char *quoted = escape_arg(*argv++);
+        strncat(buf, " ", sizeof(buf) - 1);
+        strncat(buf, quoted, sizeof(buf) - 1);
         free(quoted);
     }
 
@@ -1671,8 +1871,8 @@
     char buf[4096];
     char* quoted;
 
-    snprintf(buf, sizeof(buf), "shell:rm ");
-    quoted = dupAndQuote(filename);
+    snprintf(buf, sizeof(buf), "shell:rm -f ");
+    quoted = escape_arg(filename);
     strncat(buf, quoted, sizeof(buf)-1);
     free(quoted);
 
@@ -1691,117 +1891,186 @@
     }
 }
 
-static int check_file(const char* filename)
-{
-    struct stat st;
-
-    if (filename == NULL) {
-        return 0;
-    }
-
-    if (stat(filename, &st) != 0) {
-        fprintf(stderr, "can't find '%s' to install\n", filename);
-        return 1;
-    }
-
-    if (!S_ISREG(st.st_mode)) {
-        fprintf(stderr, "can't install '%s' because it's not a file\n", filename);
-        return 1;
-    }
-
-    return 0;
-}
-
 int install_app(transport_type transport, char* serial, int argc, char** argv)
 {
     static const char *const DATA_DEST = "/data/local/tmp/%s";
     static const char *const SD_DEST = "/sdcard/tmp/%s";
     const char* where = DATA_DEST;
-    char apk_dest[PATH_MAX];
-    char verification_dest[PATH_MAX];
-    char* apk_file;
-    char* verification_file = NULL;
-    int file_arg = -1;
-    int err;
     int i;
-    int verify_apk = 1;
+    struct stat sb;
 
     for (i = 1; i < argc; i++) {
-        if (*argv[i] != '-') {
-            file_arg = i;
-            break;
-        } else if (!strcmp(argv[i], "-i")) {
-            // Skip the installer package name.
-            i++;
-        } else if (!strcmp(argv[i], "-s")) {
+        if (!strcmp(argv[i], "-s")) {
             where = SD_DEST;
-        } else if (!strcmp(argv[i], "--algo")) {
-            verify_apk = 0;
-            i++;
-        } else if (!strcmp(argv[i], "--iv")) {
-            verify_apk = 0;
-            i++;
-        } else if (!strcmp(argv[i], "--key")) {
-            verify_apk = 0;
-            i++;
-        } else if (!strcmp(argv[i], "--abi")) {
-            i++;
         }
     }
 
-    if (file_arg < 0) {
-        fprintf(stderr, "can't find filename in arguments\n");
-        return 1;
-    } else if (file_arg + 2 < argc) {
-        fprintf(stderr, "too many files specified; only takes APK file and verifier file\n");
-        return 1;
+    // Find last APK argument.
+    // All other arguments passed through verbatim.
+    int last_apk = -1;
+    for (i = argc - 1; i >= 0; i--) {
+        char* file = argv[i];
+        char* dot = strrchr(file, '.');
+        if (dot && !strcasecmp(dot, ".apk")) {
+            if (stat(file, &sb) == -1 || !S_ISREG(sb.st_mode)) {
+                fprintf(stderr, "Invalid APK file: %s\n", file);
+                return -1;
+            }
+
+            last_apk = i;
+            break;
+        }
     }
 
-    apk_file = argv[file_arg];
-
-    if (file_arg != argc - 1) {
-        verification_file = argv[file_arg + 1];
+    if (last_apk == -1) {
+        fprintf(stderr, "Missing APK file\n");
+        return -1;
     }
 
-    if (check_file(apk_file) || check_file(verification_file)) {
-        return 1;
-    }
-
+    char* apk_file = argv[last_apk];
+    char apk_dest[PATH_MAX];
     snprintf(apk_dest, sizeof apk_dest, where, get_basename(apk_file));
-    if (verification_file != NULL) {
-        snprintf(verification_dest, sizeof(verification_dest), where, get_basename(verification_file));
-
-        if (!strcmp(apk_dest, verification_dest)) {
-            fprintf(stderr, "APK and verification file can't have the same name\n");
-            return 1;
-        }
-    }
-
-    err = do_sync_push(apk_file, apk_dest, verify_apk, 0 /* no show progress */);
+    int err = do_sync_push(apk_file, apk_dest, 0 /* no show progress */);
     if (err) {
         goto cleanup_apk;
     } else {
-        argv[file_arg] = apk_dest; /* destination name, not source location */
-    }
-
-    if (verification_file != NULL) {
-        err = do_sync_push(verification_file, verification_dest, 0 /* no verify APK */,
-                           0 /* no show progress */);
-        if (err) {
-            goto cleanup_apk;
-        } else {
-            argv[file_arg + 1] = verification_dest; /* destination name, not source location */
-        }
+        argv[last_apk] = apk_dest; /* destination name, not source location */
     }
 
     pm_command(transport, serial, argc, argv);
 
 cleanup_apk:
-    if (verification_file != NULL) {
-        delete_file(transport, serial, verification_dest);
+    delete_file(transport, serial, apk_dest);
+    return err;
+}
+
+int install_multiple_app(transport_type transport, char* serial, int argc, char** argv)
+{
+    char buf[1024];
+    int i;
+    struct stat sb;
+    unsigned long long total_size = 0;
+
+    // Find all APK arguments starting at end.
+    // All other arguments passed through verbatim.
+    int first_apk = -1;
+    for (i = argc - 1; i >= 0; i--) {
+        char* file = argv[i];
+        char* dot = strrchr(file, '.');
+        if (dot && !strcasecmp(dot, ".apk")) {
+            if (stat(file, &sb) == -1 || !S_ISREG(sb.st_mode)) {
+                fprintf(stderr, "Invalid APK file: %s\n", file);
+                return -1;
+            }
+
+            total_size += sb.st_size;
+            first_apk = i;
+        } else {
+            break;
+        }
     }
 
-    delete_file(transport, serial, apk_dest);
+    if (first_apk == -1) {
+        fprintf(stderr, "Missing APK file\n");
+        return 1;
+    }
 
-    return err;
+    snprintf(buf, sizeof(buf), "exec:pm install-create -S %lld", total_size);
+    for (i = 1; i < first_apk; i++) {
+        char *quoted = escape_arg(argv[i]);
+        strncat(buf, " ", sizeof(buf) - 1);
+        strncat(buf, quoted, sizeof(buf) - 1);
+        free(quoted);
+    }
+
+    // Create install session
+    int fd = adb_connect(buf);
+    if (fd < 0) {
+        fprintf(stderr, "Connect error for create: %s\n", adb_error());
+        return -1;
+    }
+    read_status_line(fd, buf, sizeof(buf));
+    adb_close(fd);
+
+    int session_id = -1;
+    if (!strncmp("Success", buf, 7)) {
+        char* start = strrchr(buf, '[');
+        char* end = strrchr(buf, ']');
+        if (start && end) {
+            *end = '\0';
+            session_id = strtol(start + 1, NULL, 10);
+        }
+    }
+    if (session_id < 0) {
+        fprintf(stderr, "Failed to create session\n");
+        fputs(buf, stderr);
+        return -1;
+    }
+
+    // Valid session, now stream the APKs
+    int success = 1;
+    for (i = first_apk; i < argc; i++) {
+        char* file = argv[i];
+        if (stat(file, &sb) == -1) {
+            fprintf(stderr, "Failed to stat %s\n", file);
+            success = 0;
+            goto finalize_session;
+        }
+
+        snprintf(buf, sizeof(buf), "exec:pm install-write -S %lld %d %d_%s -",
+                (long long int) sb.st_size, session_id, i, get_basename(file));
+
+        int localFd = adb_open(file, O_RDONLY);
+        if (localFd < 0) {
+            fprintf(stderr, "Failed to open %s: %s\n", file, adb_error());
+            success = 0;
+            goto finalize_session;
+        }
+
+        int remoteFd = adb_connect(buf);
+        if (remoteFd < 0) {
+            fprintf(stderr, "Connect error for write: %s\n", adb_error());
+            adb_close(localFd);
+            success = 0;
+            goto finalize_session;
+        }
+
+        copy_to_file(localFd, remoteFd);
+        read_status_line(remoteFd, buf, sizeof(buf));
+
+        adb_close(localFd);
+        adb_close(remoteFd);
+
+        if (strncmp("Success", buf, 7)) {
+            fprintf(stderr, "Failed to write %s\n", file);
+            fputs(buf, stderr);
+            success = 0;
+            goto finalize_session;
+        }
+    }
+
+finalize_session:
+    // Commit session if we streamed everything okay; otherwise abandon
+    if (success) {
+        snprintf(buf, sizeof(buf), "exec:pm install-commit %d", session_id);
+    } else {
+        snprintf(buf, sizeof(buf), "exec:pm install-abandon %d", session_id);
+    }
+
+    fd = adb_connect(buf);
+    if (fd < 0) {
+        fprintf(stderr, "Connect error for finalize: %s\n", adb_error());
+        return -1;
+    }
+    read_status_line(fd, buf, sizeof(buf));
+    adb_close(fd);
+
+    if (!strncmp("Success", buf, 7)) {
+        fputs(buf, stderr);
+        return 0;
+    } else {
+        fprintf(stderr, "Failed to finalize session\n");
+        fputs(buf, stderr);
+        return -1;
+    }
 }
diff --git a/adb/fdevent.c b/adb/fdevent.c
index 5c374a7..43e600c 100644
--- a/adb/fdevent.c
+++ b/adb/fdevent.c
@@ -28,10 +28,12 @@
 #include <stdarg.h>
 #include <stddef.h>
 
+#include "adb_trace.h"
 #include "fdevent.h"
 #include "transport.h"
 #include "sysdeps.h"
 
+#define TRACE_TAG  TRACE_FDEVENT
 
 /* !!! Do not enable DEBUG for the adb that will run as the server:
 ** both stdout and stderr are used to communicate between the client
@@ -57,16 +59,6 @@
 #define FATAL(x...) fatal(__FUNCTION__, x)
 
 #if DEBUG
-#define D(...) \
-    do { \
-        adb_mutex_lock(&D_lock);               \
-        int save_errno = errno;                \
-        fprintf(stderr, "%s::%s():", __FILE__, __FUNCTION__);  \
-        errno = save_errno;                    \
-        fprintf(stderr, __VA_ARGS__);          \
-        adb_mutex_unlock(&D_lock);             \
-        errno = save_errno;                    \
-    } while(0)
 static void dump_fde(fdevent *fde, const char *info)
 {
     adb_mutex_lock(&D_lock);
@@ -78,7 +70,6 @@
     adb_mutex_unlock(&D_lock);
 }
 #else
-#define D(...) ((void)0)
 #define dump_fde(fde, info) do { } while(0)
 #endif
 
diff --git a/adb/file_sync_client.c b/adb/file_sync_client.c
index dc4e77f..ad59e81 100644
--- a/adb/file_sync_client.c
+++ b/adb/file_sync_client.c
@@ -25,6 +25,7 @@
 #include <limits.h>
 #include <sys/types.h>
 #include <zipfile/zipfile.h>
+#include <utime.h>
 
 #include "sysdeps.h"
 #include "adb.h"
@@ -139,7 +140,8 @@
 
 static syncsendbuf send_buffer;
 
-int sync_readtime(int fd, const char *path, unsigned *timestamp)
+int sync_readtime(int fd, const char *path, unsigned int *timestamp,
+                  unsigned int *mode)
 {
     syncmsg msg;
     int len = strlen(path);
@@ -161,6 +163,7 @@
     }
 
     *timestamp = ltohl(msg.stat.time);
+    *mode = ltohl(msg.stat.mode);
     return 0;
 }
 
@@ -237,7 +240,7 @@
     if (show_progress) {
         // Determine local file size.
         struct stat st;
-        if (lstat(path, &st)) {
+        if (fstat(lfd, &st)) {
             fprintf(stderr,"cannot stat '%s': %s\n", path, strerror(errno));
             return -1;
         }
@@ -332,7 +335,7 @@
 #endif
 
 static int sync_send(int fd, const char *lpath, const char *rpath,
-                     unsigned mtime, mode_t mode, int verifyApk, int show_progress)
+                     unsigned mtime, mode_t mode, int show_progress)
 {
     syncmsg msg;
     int len, r;
@@ -347,63 +350,6 @@
     snprintf(tmp, sizeof(tmp), ",%d", mode);
     r = strlen(tmp);
 
-    if (verifyApk) {
-        int lfd;
-        zipfile_t zip;
-        zipentry_t entry;
-        int amt;
-
-        // if we are transferring an APK file, then sanity check to make sure
-        // we have a real zip file that contains an AndroidManifest.xml
-        // this requires that we read the entire file into memory.
-        lfd = adb_open(lpath, O_RDONLY);
-        if(lfd < 0) {
-            fprintf(stderr,"cannot open '%s': %s\n", lpath, strerror(errno));
-            return -1;
-        }
-
-        size = adb_lseek(lfd, 0, SEEK_END);
-        if (size == -1 || -1 == adb_lseek(lfd, 0, SEEK_SET)) {
-            fprintf(stderr, "error seeking in file '%s'\n", lpath);
-            adb_close(lfd);
-            return 1;
-        }
-
-        file_buffer = (char *)malloc(size);
-        if (file_buffer == NULL) {
-            fprintf(stderr, "could not allocate buffer for '%s'\n",
-                    lpath);
-            adb_close(lfd);
-            return 1;
-        }
-        amt = adb_read(lfd, file_buffer, size);
-        if (amt != size) {
-            fprintf(stderr, "error reading from file: '%s'\n", lpath);
-            adb_close(lfd);
-            free(file_buffer);
-            return 1;
-        }
-
-        adb_close(lfd);
-
-        zip = init_zipfile(file_buffer, size);
-        if (zip == NULL) {
-            fprintf(stderr, "file '%s' is not a valid zip file\n",
-                    lpath);
-            free(file_buffer);
-            return 1;
-        }
-
-        entry = lookup_zipentry(zip, "AndroidManifest.xml");
-        release_zipfile(zip);
-        if (entry == NULL) {
-            fprintf(stderr, "file '%s' does not contain AndroidManifest.xml\n",
-                    lpath);
-            free(file_buffer);
-            return 1;
-        }
-    }
-
     msg.req.id = ID_SEND;
     msg.req.namelen = htoll(len + r);
 
@@ -694,30 +640,33 @@
             continue;
         strcpy(stat_path, lpath);
         strcat(stat_path, de->d_name);
-        stat(stat_path, &st);
 
-        if (S_ISDIR(st.st_mode)) {
-            ci = mkcopyinfo(lpath, rpath, name, 1);
-            ci->next = dirlist;
-            dirlist = ci;
-        } else {
-            ci = mkcopyinfo(lpath, rpath, name, 0);
-            if(lstat(ci->src, &st)) {
-                fprintf(stderr,"cannot stat '%s': %s\n", ci->src, strerror(errno));
-                free(ci);
-                closedir(d);
-                return -1;
-            }
-            if(!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
-                fprintf(stderr, "skipping special file '%s'\n", ci->src);
-                free(ci);
+        if(!lstat(stat_path, &st)) {
+            if (S_ISDIR(st.st_mode)) {
+                ci = mkcopyinfo(lpath, rpath, name, 1);
+                ci->next = dirlist;
+                dirlist = ci;
             } else {
-                ci->time = st.st_mtime;
-                ci->mode = st.st_mode;
-                ci->size = st.st_size;
-                ci->next = *filelist;
-                *filelist = ci;
+                ci = mkcopyinfo(lpath, rpath, name, 0);
+                if(lstat(ci->src, &st)) {
+                    fprintf(stderr,"cannot stat '%s': %s\n", ci->src, strerror(errno));
+                    free(ci);
+                    closedir(d);
+                    return -1;
+                }
+                if(!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
+                    fprintf(stderr, "skipping special file '%s'\n", ci->src);
+                    free(ci);
+                } else {
+                    ci->time = st.st_mtime;
+                    ci->mode = st.st_mode;
+                    ci->size = st.st_size;
+                    ci->next = *filelist;
+                    *filelist = ci;
+                }
             }
+        } else {
+            fprintf(stderr, "cannot lstat '%s': %s\n",stat_path , strerror(errno));
         }
     }
 
@@ -783,7 +732,7 @@
         if(ci->flag == 0) {
             fprintf(stderr,"%spush: %s -> %s\n", listonly ? "would " : "", ci->src, ci->dst);
             if(!listonly &&
-               sync_send(fd, ci->src, ci->dst, ci->time, ci->mode, 0 /* no verify APK */,
+               sync_send(fd, ci->src, ci->dst, ci->time, ci->mode,
                          0 /* no show progress */)) {
                 return 1;
             }
@@ -802,7 +751,7 @@
 }
 
 
-int do_sync_push(const char *lpath, const char *rpath, int verifyApk, int show_progress)
+int do_sync_push(const char *lpath, const char *rpath, int show_progress)
 {
     struct stat st;
     unsigned mode;
@@ -849,7 +798,7 @@
             rpath = tmp;
         }
         BEGIN();
-        if(sync_send(fd, lpath, rpath, st.st_mtime, st.st_mode, verifyApk, show_progress)) {
+        if(sync_send(fd, lpath, rpath, st.st_mtime, st.st_mode, show_progress)) {
             return 1;
         } else {
             END();
@@ -931,8 +880,21 @@
     return 0;
 }
 
+static int set_time_and_mode(const char *lpath, unsigned int time, unsigned int mode)
+{
+    struct utimbuf times = { time, time };
+    int r1 = utime(lpath, &times);
+
+    /* use umask for permissions */
+    mode_t mask=umask(0000);
+    umask(mask);
+    int r2 = chmod(lpath, mode & ~mask);
+
+    return r1 ? : r2;
+}
+
 static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath,
-                                 int checktimestamps)
+                                 int copy_attrs)
 {
     copyinfo *filelist = 0;
     copyinfo *ci, *next;
@@ -962,26 +924,6 @@
         return -1;
     }
 
-#if 0
-    if (checktimestamps) {
-        for (ci = filelist; ci != 0; ci = ci->next) {
-            if (sync_start_readtime(fd, ci->dst)) {
-                return 1;
-            }
-        }
-        for (ci = filelist; ci != 0; ci = ci->next) {
-            unsigned int timestamp, mode, size;
-            if (sync_finish_readtime(fd, &timestamp, &mode, &size))
-                return 1;
-            if (size == ci->size) {
-                /* for links, we cannot update the atime/mtime */
-                if ((S_ISREG(ci->mode & mode) && timestamp == ci->time) ||
-                    (S_ISLNK(ci->mode & mode) && timestamp >= ci->time))
-                    ci->flag = 1;
-            }
-        }
-    }
-#endif
     for (ci = filelist; ci != 0; ci = next) {
         next = ci->next;
         if (ci->flag == 0) {
@@ -989,6 +931,10 @@
             if (sync_recv(fd, ci->src, ci->dst, 0 /* no show progress */)) {
                 return 1;
             }
+
+            if (copy_attrs && set_time_and_mode(ci->dst, ci->time, ci->mode)) {
+               return 1;
+            }
             pulled++;
         } else {
             skipped++;
@@ -1003,9 +949,9 @@
     return 0;
 }
 
-int do_sync_pull(const char *rpath, const char *lpath, int show_progress)
+int do_sync_pull(const char *rpath, const char *lpath, int show_progress, int copy_attrs)
 {
-    unsigned mode;
+    unsigned mode, time;
     struct stat st;
 
     int fd;
@@ -1016,7 +962,7 @@
         return 1;
     }
 
-    if(sync_readmode(fd, rpath, &mode)) {
+    if(sync_readtime(fd, rpath, &time, &mode)) {
         return 1;
     }
     if(mode == 0) {
@@ -1047,13 +993,15 @@
         if (sync_recv(fd, rpath, lpath, show_progress)) {
             return 1;
         } else {
+            if (copy_attrs && set_time_and_mode(lpath, time, mode))
+                return 1;
             END();
             sync_quit(fd);
             return 0;
         }
     } else if(S_ISDIR(mode)) {
         BEGIN();
-        if (copy_remote_dir_local(fd, rpath, lpath, 0)) {
+        if (copy_remote_dir_local(fd, rpath, lpath, copy_attrs)) {
             return 1;
         } else {
             END();
diff --git a/adb/file_sync_service.c b/adb/file_sync_service.c
index 1d80d26..7933858 100644
--- a/adb/file_sync_service.c
+++ b/adb/file_sync_service.c
@@ -39,6 +39,11 @@
     return (strncmp(SYSTEM, name, strlen(SYSTEM)) == 0);
 }
 
+static bool is_on_vendor(const char *name) {
+    const char *VENDOR = "/vendor/";
+    return (strncmp(VENDOR, name, strlen(VENDOR)) == 0);
+}
+
 static int mkdirs(char *name)
 {
     int ret;
@@ -54,7 +59,7 @@
         x = adb_dirstart(x);
         if(x == 0) return 0;
         *x = 0;
-        if (is_on_system(name)) {
+        if (is_on_system(name) || is_on_vendor(name)) {
             fs_config(name, 1, &uid, &gid, &mode, &cap);
         }
         ret = adb_mkdir(name, mode);
@@ -178,18 +183,18 @@
     unsigned int timestamp = 0;
     int fd;
 
-    fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL, mode);
+    fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode);
     if(fd < 0 && errno == ENOENT) {
         if(mkdirs(path) != 0) {
             if(fail_errno(s))
                 return -1;
             fd = -1;
         } else {
-            fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL, mode);
+            fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode);
         }
     }
     if(fd < 0 && errno == EEXIST) {
-        fd = adb_open_mode(path, O_WRONLY, mode);
+        fd = adb_open_mode(path, O_WRONLY | O_CLOEXEC, mode);
     }
     if(fd < 0) {
         if(fail_errno(s))
@@ -369,7 +374,7 @@
         if(*tmp == '/') {
             tmp++;
         }
-        if (is_on_system(path)) {
+        if (is_on_system(path) || is_on_vendor(path)) {
             fs_config(tmp, 0, &uid, &gid, &mode, &cap);
         }
         ret = handle_send_file(s, path, uid, gid, mode, buffer, do_unlink);
@@ -383,7 +388,7 @@
     syncmsg msg;
     int fd, r;
 
-    fd = adb_open(path, O_RDONLY);
+    fd = adb_open(path, O_RDONLY | O_CLOEXEC);
     if(fd < 0) {
         if(fail_errno(s)) return -1;
         return 0;
diff --git a/adb/file_sync_service.h b/adb/file_sync_service.h
index 3e7e096..5dd2e80 100644
--- a/adb/file_sync_service.h
+++ b/adb/file_sync_service.h
@@ -78,9 +78,9 @@
 
 void file_sync_service(int fd, void *cookie);
 int do_sync_ls(const char *path);
-int do_sync_push(const char *lpath, const char *rpath, int verifyApk, int show_progress);
+int do_sync_push(const char *lpath, const char *rpath, int show_progress);
 int do_sync_sync(const char *lpath, const char *rpath, int listonly);
-int do_sync_pull(const char *rpath, const char *lpath, int show_progress);
+int do_sync_pull(const char *rpath, const char *lpath, int show_progress, int pullTime);
 
 #define SYNC_DATA_MAX (64*1024)
 
diff --git a/adb/remount_service.c b/adb/remount_service.c
index d3a649b..72d15a1 100644
--- a/adb/remount_service.c
+++ b/adb/remount_service.c
@@ -29,6 +29,7 @@
 
 
 static int system_ro = 1;
+static int vendor_ro = 1;
 
 /* Returns the device used to mount a directory in /proc/mounts */
 static char *find_mount(const char *dir)
@@ -39,7 +40,7 @@
     const char delims[] = "\n";
     char buf[4096];
 
-    fd = unix_open("/proc/mounts", O_RDONLY);
+    fd = unix_open("/proc/mounts", O_RDONLY | O_CLOEXEC);
     if (fd < 0)
         return NULL;
 
@@ -67,34 +68,43 @@
     return NULL;
 }
 
+static int hasVendorPartition()
+{
+    struct stat info;
+    if (!lstat("/vendor", &info))
+        if ((info.st_mode & S_IFMT) == S_IFDIR)
+          return true;
+    return false;
+}
+
 /* Init mounts /system as read only, remount to enable writes. */
-static int remount_system()
+static int remount(const char* dir, int* dir_ro)
 {
     char *dev;
     int fd;
     int OFF = 0;
 
-    if (system_ro == 0) {
+    if (dir_ro == 0) {
         return 0;
     }
 
-    dev = find_mount("/system");
+    dev = find_mount(dir);
 
     if (!dev)
         return -1;
 
-    fd = unix_open(dev, O_RDONLY);
+    fd = unix_open(dev, O_RDONLY | O_CLOEXEC);
     if (fd < 0)
         return -1;
 
     ioctl(fd, BLKROSET, &OFF);
     adb_close(fd);
 
-    system_ro = mount(dev, "/system", "none", MS_REMOUNT, NULL);
+    *dir_ro = mount(dev, dir, "none", MS_REMOUNT, NULL);
 
     free(dev);
 
-    return system_ro;
+    return *dir_ro;
 }
 
 static void write_string(int fd, const char* str)
@@ -104,16 +114,25 @@
 
 void remount_service(int fd, void *cookie)
 {
-    int ret = remount_system();
-
-    if (!ret)
-       write_string(fd, "remount succeeded\n");
-    else {
-        char    buffer[200];
-        snprintf(buffer, sizeof(buffer), "remount failed: %s\n", strerror(errno));
+    char buffer[200];
+    if (remount("/system", &system_ro)) {
+        snprintf(buffer, sizeof(buffer), "remount of system failed: %s\n",strerror(errno));
         write_string(fd, buffer);
     }
 
+    if (hasVendorPartition()) {
+        if (remount("/vendor", &vendor_ro)) {
+            snprintf(buffer, sizeof(buffer), "remount of vendor failed: %s\n",strerror(errno));
+            write_string(fd, buffer);
+        }
+    }
+
+    if (!system_ro && (!vendor_ro || !hasVendorPartition()))
+        write_string(fd, "remount succeeded\n");
+    else {
+        write_string(fd, "remount failed\n");
+    }
+
     adb_close(fd);
 }
 
diff --git a/adb/services.c b/adb/services.c
index 7b809da..e61371a 100644
--- a/adb/services.c
+++ b/adb/services.c
@@ -184,25 +184,38 @@
 }
 
 #if !ADB_HOST
-static int create_subprocess(const char *cmd, const char *arg0, const char *arg1, pid_t *pid)
+
+static void init_subproc_child()
 {
+    setsid();
+
+    // Set OOM score adjustment to prevent killing
+    int fd = adb_open("/proc/self/oom_score_adj", O_WRONLY | O_CLOEXEC);
+    if (fd >= 0) {
+        adb_write(fd, "0", 1);
+        adb_close(fd);
+    } else {
+       D("adb: unable to update oom_score_adj\n");
+    }
+}
+
+static int create_subproc_pty(const char *cmd, const char *arg0, const char *arg1, pid_t *pid)
+{
+    D("create_subproc_pty(cmd=%s, arg0=%s, arg1=%s)\n", cmd, arg0, arg1);
 #ifdef HAVE_WIN32_PROC
-    D("create_subprocess(cmd=%s, arg0=%s, arg1=%s)\n", cmd, arg0, arg1);
-    fprintf(stderr, "error: create_subprocess not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1);
+    fprintf(stderr, "error: create_subproc_pty not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1);
     return -1;
 #else /* !HAVE_WIN32_PROC */
-    char *devname;
     int ptm;
 
-    ptm = unix_open("/dev/ptmx", O_RDWR); // | O_NOCTTY);
+    ptm = unix_open("/dev/ptmx", O_RDWR | O_CLOEXEC); // | O_NOCTTY);
     if(ptm < 0){
         printf("[ cannot open /dev/ptmx - %s ]\n",strerror(errno));
         return -1;
     }
-    fcntl(ptm, F_SETFD, FD_CLOEXEC);
 
-    if(grantpt(ptm) || unlockpt(ptm) ||
-       ((devname = (char*) ptsname(ptm)) == 0)){
+    char devname[64];
+    if(grantpt(ptm) || unlockpt(ptm) || ptsname_r(ptm, devname, sizeof(devname)) != 0) {
         printf("[ trouble with /dev/ptmx - %s ]\n", strerror(errno));
         adb_close(ptm);
         return -1;
@@ -215,47 +228,75 @@
         return -1;
     }
 
-    if(*pid == 0){
-        int pts;
+    if (*pid == 0) {
+        init_subproc_child();
 
-        setsid();
-
-        pts = unix_open(devname, O_RDWR);
-        if(pts < 0) {
+        int pts = unix_open(devname, O_RDWR | O_CLOEXEC);
+        if (pts < 0) {
             fprintf(stderr, "child failed to open pseudo-term slave: %s\n", devname);
             exit(-1);
         }
 
-        dup2(pts, 0);
-        dup2(pts, 1);
-        dup2(pts, 2);
+        dup2(pts, STDIN_FILENO);
+        dup2(pts, STDOUT_FILENO);
+        dup2(pts, STDERR_FILENO);
 
         adb_close(pts);
         adb_close(ptm);
 
-        // set OOM adjustment to zero
-        char text[64];
-        snprintf(text, sizeof text, "/proc/%d/oom_adj", getpid());
-        int fd = adb_open(text, O_WRONLY);
-        if (fd >= 0) {
-            adb_write(fd, "0", 1);
-            adb_close(fd);
-        } else {
-           D("adb: unable to open %s\n", text);
-        }
         execl(cmd, cmd, arg0, arg1, NULL);
         fprintf(stderr, "- exec '%s' failed: %s (%d) -\n",
                 cmd, strerror(errno), errno);
         exit(-1);
     } else {
-        // Don't set child's OOM adjustment to zero.
-        // Let the child do it itself, as sometimes the parent starts
-        // running before the child has a /proc/pid/oom_adj.
-        // """adb: unable to open /proc/644/oom_adj""" seen in some logs.
         return ptm;
     }
 #endif /* !HAVE_WIN32_PROC */
 }
+
+static int create_subproc_raw(const char *cmd, const char *arg0, const char *arg1, pid_t *pid)
+{
+    D("create_subproc_raw(cmd=%s, arg0=%s, arg1=%s)\n", cmd, arg0, arg1);
+#ifdef HAVE_WIN32_PROC
+    fprintf(stderr, "error: create_subproc_raw not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1);
+    return -1;
+#else /* !HAVE_WIN32_PROC */
+
+    // 0 is parent socket, 1 is child socket
+    int sv[2];
+    if (unix_socketpair(AF_UNIX, SOCK_STREAM, 0, sv) < 0) {
+        printf("[ cannot create socket pair - %s ]\n", strerror(errno));
+        return -1;
+    }
+
+    *pid = fork();
+    if (*pid < 0) {
+        printf("- fork failed: %s -\n", strerror(errno));
+        adb_close(sv[0]);
+        adb_close(sv[1]);
+        return -1;
+    }
+
+    if (*pid == 0) {
+        adb_close(sv[0]);
+        init_subproc_child();
+
+        dup2(sv[1], STDIN_FILENO);
+        dup2(sv[1], STDOUT_FILENO);
+        dup2(sv[1], STDERR_FILENO);
+
+        adb_close(sv[1]);
+
+        execl(cmd, cmd, arg0, arg1, NULL);
+        fprintf(stderr, "- exec '%s' failed: %s (%d) -\n",
+                cmd, strerror(errno), errno);
+        exit(-1);
+    } else {
+        adb_close(sv[1]);
+        return sv[0];
+    }
+#endif /* !HAVE_WIN32_PROC */
+}
 #endif  /* !ABD_HOST */
 
 #if ADB_HOST
@@ -296,18 +337,32 @@
     }
 }
 
-static int create_subproc_thread(const char *name)
+static int create_subproc_thread(const char *name, const subproc_mode mode)
 {
     stinfo *sti;
     adb_thread_t t;
     int ret_fd;
-    pid_t pid;
-    if(name) {
-        ret_fd = create_subprocess(SHELL_COMMAND, "-c", name, &pid);
+    pid_t pid = -1;
+
+    const char *arg0, *arg1;
+    if (name == 0 || *name == 0) {
+        arg0 = "-"; arg1 = 0;
     } else {
-        ret_fd = create_subprocess(SHELL_COMMAND, "-", 0, &pid);
+        arg0 = "-c"; arg1 = name;
     }
-    D("create_subprocess() ret_fd=%d pid=%d\n", ret_fd, pid);
+
+    switch (mode) {
+    case SUBPROC_PTY:
+        ret_fd = create_subproc_pty(SHELL_COMMAND, arg0, arg1, &pid);
+        break;
+    case SUBPROC_RAW:
+        ret_fd = create_subproc_raw(SHELL_COMMAND, arg0, arg1, &pid);
+        break;
+    default:
+        fprintf(stderr, "invalid subproc_mode %d\n", mode);
+        return -1;
+    }
+    D("create_subproc ret_fd=%d pid=%d\n", ret_fd, pid);
 
     sti = malloc(sizeof(stinfo));
     if(sti == 0) fatal("cannot allocate stinfo");
@@ -315,14 +370,14 @@
     sti->cookie = (void*) (uintptr_t) pid;
     sti->fd = ret_fd;
 
-    if(adb_thread_create( &t, service_bootstrap_func, sti)){
+    if (adb_thread_create(&t, service_bootstrap_func, sti)) {
         free(sti);
         adb_close(ret_fd);
-        printf("cannot create service thread\n");
+        fprintf(stderr, "cannot create service thread\n");
         return -1;
     }
 
-    D("service thread started, fd=%d pid=%d\n",ret_fd, pid);
+    D("service thread started, fd=%d pid=%d\n", ret_fd, pid);
     return ret_fd;
 }
 #endif
@@ -361,33 +416,41 @@
 #endif
 #if !ADB_HOST
     } else if(!strncmp("dev:", name, 4)) {
-        ret = unix_open(name + 4, O_RDWR);
+        ret = unix_open(name + 4, O_RDWR | O_CLOEXEC);
     } else if(!strncmp(name, "framebuffer:", 12)) {
         ret = create_service_thread(framebuffer_service, 0);
     } else if (!strncmp(name, "jdwp:", 5)) {
         ret = create_jdwp_connection_fd(atoi(name+5));
     } else if(!HOST && !strncmp(name, "shell:", 6)) {
-        if(name[6]) {
-            ret = create_subproc_thread(name + 6);
-        } else {
-            ret = create_subproc_thread(0);
-        }
+        ret = create_subproc_thread(name + 6, SUBPROC_PTY);
+    } else if(!HOST && !strncmp(name, "exec:", 5)) {
+        ret = create_subproc_thread(name + 5, SUBPROC_RAW);
     } else if(!strncmp(name, "sync:", 5)) {
         ret = create_service_thread(file_sync_service, NULL);
     } else if(!strncmp(name, "remount:", 8)) {
         ret = create_service_thread(remount_service, NULL);
     } else if(!strncmp(name, "reboot:", 7)) {
         void* arg = strdup(name + 7);
-        if(arg == 0) return -1;
+        if (arg == NULL) return -1;
         ret = create_service_thread(reboot_service, arg);
     } else if(!strncmp(name, "root:", 5)) {
         ret = create_service_thread(restart_root_service, NULL);
     } else if(!strncmp(name, "backup:", 7)) {
-        char* arg = strdup(name+7);
+        char* arg = strdup(name + 7);
         if (arg == NULL) return -1;
-        ret = backup_service(BACKUP, arg);
+        char* c = arg;
+        for (; *c != '\0'; c++) {
+            if (*c == ':')
+                *c = ' ';
+        }
+        char* cmd;
+        if (asprintf(&cmd, "/system/bin/bu backup %s", arg) != -1) {
+            ret = create_subproc_thread(cmd, SUBPROC_RAW);
+            free(cmd);
+        }
+        free(arg);
     } else if(!strncmp(name, "restore:", 8)) {
-        ret = backup_service(RESTORE, NULL);
+        ret = create_subproc_thread("/system/bin/bu restore", SUBPROC_RAW);
     } else if(!strncmp(name, "tcpip:", 6)) {
         int port;
         if (sscanf(name + 6, "%d", &port) == 0) {
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index ba4306f..cc1f839 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -26,8 +26,8 @@
 
 #ifdef _WIN32
 
-#include <windows.h>
 #include <winsock2.h>
+#include <windows.h>
 #include <ws2tcpip.h>
 #include <process.h>
 #include <fcntl.h>
@@ -35,6 +35,7 @@
 #include <sys/stat.h>
 #include <errno.h>
 #include <ctype.h>
+#include <direct.h>
 
 #define OS_PATH_SEPARATOR '\\'
 #define OS_PATH_SEPARATOR_STR "\\"
diff --git a/adb/sysdeps_win32.c b/adb/sysdeps_win32.c
index 29f58ec..b082c6d 100644
--- a/adb/sysdeps_win32.c
+++ b/adb/sysdeps_win32.c
@@ -1,6 +1,6 @@
 #include "sysdeps.h"
-#include <windows.h>
 #include <winsock2.h>
+#include <windows.h>
 #include <stdio.h>
 #include <errno.h>
 #define  TRACE_TAG  TRACE_SYSDEPS
@@ -1549,7 +1549,7 @@
      * reset" event that will remain set once it was set. */
     main_event = CreateEvent(NULL, TRUE, FALSE, NULL);
     if (main_event == NULL) {
-        D("Unable to create main event. Error: %d", GetLastError());
+        D("Unable to create main event. Error: %d", (int)GetLastError());
         free(threads);
         return (int)WAIT_FAILED;
     }
diff --git a/adb/usb_linux.c b/adb/usb_linux.c
index 8ff753e..f16bdd0 100644
--- a/adb/usb_linux.c
+++ b/adb/usb_linux.c
@@ -170,7 +170,7 @@
             }
 
 //            DBGX("[ scanning %s ]\n", devname);
-            if((fd = unix_open(devname, O_RDONLY)) < 0) {
+            if((fd = unix_open(devname, O_RDONLY | O_CLOEXEC)) < 0) {
                 continue;
             }
 
@@ -597,10 +597,10 @@
     usb->mark = 1;
     usb->reaper_thread = 0;
 
-    usb->desc = unix_open(usb->fname, O_RDWR);
+    usb->desc = unix_open(usb->fname, O_RDWR | O_CLOEXEC);
     if(usb->desc < 0) {
         /* if we fail, see if have read-only access */
-        usb->desc = unix_open(usb->fname, O_RDONLY);
+        usb->desc = unix_open(usb->fname, O_RDONLY | O_CLOEXEC);
         if(usb->desc < 0) goto fail;
         usb->writeable = 0;
         D("[ usb open read-only %s fd = %d]\n", usb->fname, usb->desc);
diff --git a/adb/usb_osx.c b/adb/usb_osx.c
index 45ce444..ca4f2af 100644
--- a/adb/usb_osx.c
+++ b/adb/usb_osx.c
@@ -512,14 +512,18 @@
         return -1;
     }
 
-    result =
-      (*handle->interface)->ReadPipe(handle->interface,
-                                    handle->bulkIn, buf, &numBytes);
+    result = (*handle->interface)->ReadPipe(handle->interface, handle->bulkIn, buf, &numBytes);
 
-    if (0 == result)
+    if (kIOUSBPipeStalled == result) {
+        DBG(" Pipe stalled, clearing stall.\n");
+        (*handle->interface)->ClearPipeStall(handle->interface, handle->bulkIn);
+        result = (*handle->interface)->ReadPipe(handle->interface, handle->bulkIn, buf, &numBytes);
+    }
+
+    if (kIOReturnSuccess == result)
         return 0;
     else {
-        DBG("ERR: usb_read failed with status %d\n", result);
+        DBG("ERR: usb_read failed with status %x\n", result);
     }
 
     return -1;
diff --git a/adb/usb_windows.c b/adb/usb_windows.c
index 1309a78..b7ad913 100644
--- a/adb/usb_windows.c
+++ b/adb/usb_windows.c
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <winsock2.h>
 #include <windows.h>
 #include <winerror.h>
 #include <errno.h>
diff --git a/charger/Android.mk b/charger/Android.mk
deleted file mode 100644
index 40c7d78..0000000
--- a/charger/Android.mk
+++ /dev/null
@@ -1,61 +0,0 @@
-# Copyright 2011 The Android Open Source Project
-
-ifneq ($(BUILD_TINY_ANDROID),true)
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-	charger.c
-
-ifeq ($(strip $(BOARD_CHARGER_DISABLE_INIT_BLANK)),true)
-LOCAL_CFLAGS := -DCHARGER_DISABLE_INIT_BLANK
-endif
-
-ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true)
-LOCAL_CFLAGS += -DCHARGER_ENABLE_SUSPEND
-endif
-
-LOCAL_MODULE := charger
-LOCAL_MODULE_TAGS := optional
-LOCAL_FORCE_STATIC_EXECUTABLE := true
-LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)
-LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED)
-
-LOCAL_C_INCLUDES := bootable/recovery
-
-LOCAL_STATIC_LIBRARIES := libminui libpng
-ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true)
-LOCAL_STATIC_LIBRARIES += libsuspend
-endif
-LOCAL_STATIC_LIBRARIES += libz libstdc++ libcutils liblog libm libc
-
-include $(BUILD_EXECUTABLE)
-
-define _add-charger-image
-include $$(CLEAR_VARS)
-LOCAL_MODULE := system_core_charger_$(notdir $(1))
-LOCAL_MODULE_STEM := $(notdir $(1))
-_img_modules += $$(LOCAL_MODULE)
-LOCAL_SRC_FILES := $1
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $$(TARGET_ROOT_OUT)/res/images/charger
-include $$(BUILD_PREBUILT)
-endef
-
-_img_modules :=
-_images :=
-$(foreach _img, $(call find-subdir-subdir-files, "images", "*.png"), \
-  $(eval $(call _add-charger-image,$(_img))))
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := charger_res_images
-LOCAL_MODULE_TAGS := optional
-LOCAL_REQUIRED_MODULES := $(_img_modules)
-include $(BUILD_PHONY_PACKAGE)
-
-_add-charger-image :=
-_img_modules :=
-
-endif
diff --git a/charger/charger.c b/charger/charger.c
deleted file mode 100644
index 15add87..0000000
--- a/charger/charger.c
+++ /dev/null
@@ -1,1026 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-//#define DEBUG_UEVENTS
-#define CHARGER_KLOG_LEVEL 6
-
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/input.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/poll.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/un.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <sys/socket.h>
-#include <linux/netlink.h>
-
-#include <cutils/android_reboot.h>
-#include <cutils/klog.h>
-#include <cutils/list.h>
-#include <cutils/misc.h>
-#include <cutils/uevent.h>
-#include <cutils/properties.h>
-
-#ifdef CHARGER_ENABLE_SUSPEND
-#include <suspend/autosuspend.h>
-#endif
-
-#include "minui/minui.h"
-
-char *locale;
-
-#ifndef max
-#define max(a,b) ((a) > (b) ? (a) : (b))
-#endif
-
-#ifndef min
-#define min(a,b) ((a) < (b) ? (a) : (b))
-#endif
-
-#define ARRAY_SIZE(x)           (sizeof(x)/sizeof(x[0]))
-
-#define MSEC_PER_SEC            (1000LL)
-#define NSEC_PER_MSEC           (1000000LL)
-
-#define BATTERY_UNKNOWN_TIME    (2 * MSEC_PER_SEC)
-#define POWER_ON_KEY_TIME       (2 * MSEC_PER_SEC)
-#define UNPLUGGED_SHUTDOWN_TIME (10 * MSEC_PER_SEC)
-
-#define BATTERY_FULL_THRESH     95
-
-#define LAST_KMSG_PATH          "/proc/last_kmsg"
-#define LAST_KMSG_MAX_SZ        (32 * 1024)
-
-#define LOGE(x...) do { KLOG_ERROR("charger", x); } while (0)
-#define LOGI(x...) do { KLOG_INFO("charger", x); } while (0)
-#define LOGV(x...) do { KLOG_DEBUG("charger", x); } while (0)
-
-struct key_state {
-    bool pending;
-    bool down;
-    int64_t timestamp;
-};
-
-struct power_supply {
-    struct listnode list;
-    char name[256];
-    char type[32];
-    bool online;
-    bool valid;
-    char cap_path[PATH_MAX];
-};
-
-struct frame {
-    int disp_time;
-    int min_capacity;
-    bool level_only;
-
-    gr_surface surface;
-};
-
-struct animation {
-    bool run;
-
-    struct frame *frames;
-    int cur_frame;
-    int num_frames;
-
-    int cur_cycle;
-    int num_cycles;
-
-    /* current capacity being animated */
-    int capacity;
-};
-
-struct charger {
-    int64_t next_screen_transition;
-    int64_t next_key_check;
-    int64_t next_pwr_check;
-
-    struct key_state keys[KEY_MAX + 1];
-    int uevent_fd;
-
-    struct listnode supplies;
-    int num_supplies;
-    int num_supplies_online;
-
-    struct animation *batt_anim;
-    gr_surface surf_unknown;
-
-    struct power_supply *battery;
-};
-
-struct uevent {
-    const char *action;
-    const char *path;
-    const char *subsystem;
-    const char *ps_name;
-    const char *ps_type;
-    const char *ps_online;
-};
-
-static struct frame batt_anim_frames[] = {
-    {
-        .disp_time = 750,
-        .min_capacity = 0,
-    },
-    {
-        .disp_time = 750,
-        .min_capacity = 20,
-    },
-    {
-        .disp_time = 750,
-        .min_capacity = 40,
-    },
-    {
-        .disp_time = 750,
-        .min_capacity = 60,
-    },
-    {
-        .disp_time = 750,
-        .min_capacity = 80,
-        .level_only = true,
-    },
-    {
-        .disp_time = 750,
-        .min_capacity = BATTERY_FULL_THRESH,
-    },
-};
-
-static struct animation battery_animation = {
-    .frames = batt_anim_frames,
-    .num_frames = ARRAY_SIZE(batt_anim_frames),
-    .num_cycles = 3,
-};
-
-static struct charger charger_state = {
-    .batt_anim = &battery_animation,
-};
-
-static int char_width;
-static int char_height;
-
-/* current time in milliseconds */
-static int64_t curr_time_ms(void)
-{
-    struct timespec tm;
-    clock_gettime(CLOCK_MONOTONIC, &tm);
-    return tm.tv_sec * MSEC_PER_SEC + (tm.tv_nsec / NSEC_PER_MSEC);
-}
-
-static void clear_screen(void)
-{
-    gr_color(0, 0, 0, 255);
-    gr_clear();
-}
-
-#define MAX_KLOG_WRITE_BUF_SZ 256
-
-static void dump_last_kmsg(void)
-{
-    char *buf;
-    char *ptr;
-    unsigned sz = 0;
-    int len;
-
-    LOGI("\n");
-    LOGI("*************** LAST KMSG ***************\n");
-    LOGI("\n");
-    buf = load_file(LAST_KMSG_PATH, &sz);
-    if (!buf || !sz) {
-        LOGI("last_kmsg not found. Cold reset?\n");
-        goto out;
-    }
-
-    len = min(sz, LAST_KMSG_MAX_SZ);
-    ptr = buf + (sz - len);
-
-    while (len > 0) {
-        int cnt = min(len, MAX_KLOG_WRITE_BUF_SZ);
-        char yoink;
-        char *nl;
-
-        nl = memrchr(ptr, '\n', cnt - 1);
-        if (nl)
-            cnt = nl - ptr + 1;
-
-        yoink = ptr[cnt];
-        ptr[cnt] = '\0';
-        klog_write(6, "<6>%s", ptr);
-        ptr[cnt] = yoink;
-
-        len -= cnt;
-        ptr += cnt;
-    }
-
-    free(buf);
-
-out:
-    LOGI("\n");
-    LOGI("************* END LAST KMSG *************\n");
-    LOGI("\n");
-}
-
-static int read_file(const char *path, char *buf, size_t sz)
-{
-    int fd;
-    size_t cnt;
-
-    fd = open(path, O_RDONLY, 0);
-    if (fd < 0)
-        goto err;
-
-    cnt = read(fd, buf, sz - 1);
-    if (cnt <= 0)
-        goto err;
-    buf[cnt] = '\0';
-    if (buf[cnt - 1] == '\n') {
-        cnt--;
-        buf[cnt] = '\0';
-    }
-
-    close(fd);
-    return cnt;
-
-err:
-    if (fd >= 0)
-        close(fd);
-    return -1;
-}
-
-static int read_file_int(const char *path, int *val)
-{
-    char buf[32];
-    int ret;
-    int tmp;
-    char *end;
-
-    ret = read_file(path, buf, sizeof(buf));
-    if (ret < 0)
-        return -1;
-
-    tmp = strtol(buf, &end, 0);
-    if (end == buf ||
-        ((end < buf+sizeof(buf)) && (*end != '\n' && *end != '\0')))
-        goto err;
-
-    *val = tmp;
-    return 0;
-
-err:
-    return -1;
-}
-
-static int get_battery_capacity(struct charger *charger)
-{
-    int ret;
-    int batt_cap = -1;
-
-    if (!charger->battery)
-        return -1;
-
-    ret = read_file_int(charger->battery->cap_path, &batt_cap);
-    if (ret < 0 || batt_cap > 100) {
-        batt_cap = -1;
-    }
-
-    return batt_cap;
-}
-
-static struct power_supply *find_supply(struct charger *charger,
-                                        const char *name)
-{
-    struct listnode *node;
-    struct power_supply *supply;
-
-    list_for_each(node, &charger->supplies) {
-        supply = node_to_item(node, struct power_supply, list);
-        if (!strncmp(name, supply->name, sizeof(supply->name)))
-            return supply;
-    }
-    return NULL;
-}
-
-static struct power_supply *add_supply(struct charger *charger,
-                                       const char *name, const char *type,
-                                       const char *path, bool online)
-{
-    struct power_supply *supply;
-
-    supply = calloc(1, sizeof(struct power_supply));
-    if (!supply)
-        return NULL;
-
-    strlcpy(supply->name, name, sizeof(supply->name));
-    strlcpy(supply->type, type, sizeof(supply->type));
-    snprintf(supply->cap_path, sizeof(supply->cap_path),
-             "/sys/%s/capacity", path);
-    supply->online = online;
-    list_add_tail(&charger->supplies, &supply->list);
-    charger->num_supplies++;
-    LOGV("... added %s %s %d\n", supply->name, supply->type, online);
-    return supply;
-}
-
-static void remove_supply(struct charger *charger, struct power_supply *supply)
-{
-    if (!supply)
-        return;
-    list_remove(&supply->list);
-    charger->num_supplies--;
-    free(supply);
-}
-
-#ifdef CHARGER_ENABLE_SUSPEND
-static int request_suspend(bool enable)
-{
-    if (enable)
-        return autosuspend_enable();
-    else
-        return autosuspend_disable();
-}
-#else
-static int request_suspend(bool enable)
-{
-    return 0;
-}
-#endif
-
-static void parse_uevent(const char *msg, struct uevent *uevent)
-{
-    uevent->action = "";
-    uevent->path = "";
-    uevent->subsystem = "";
-    uevent->ps_name = "";
-    uevent->ps_online = "";
-    uevent->ps_type = "";
-
-    /* currently ignoring SEQNUM */
-    while (*msg) {
-#ifdef DEBUG_UEVENTS
-        LOGV("uevent str: %s\n", msg);
-#endif
-        if (!strncmp(msg, "ACTION=", 7)) {
-            msg += 7;
-            uevent->action = msg;
-        } else if (!strncmp(msg, "DEVPATH=", 8)) {
-            msg += 8;
-            uevent->path = msg;
-        } else if (!strncmp(msg, "SUBSYSTEM=", 10)) {
-            msg += 10;
-            uevent->subsystem = msg;
-        } else if (!strncmp(msg, "POWER_SUPPLY_NAME=", 18)) {
-            msg += 18;
-            uevent->ps_name = msg;
-        } else if (!strncmp(msg, "POWER_SUPPLY_ONLINE=", 20)) {
-            msg += 20;
-            uevent->ps_online = msg;
-        } else if (!strncmp(msg, "POWER_SUPPLY_TYPE=", 18)) {
-            msg += 18;
-            uevent->ps_type = msg;
-        }
-
-        /* advance to after the next \0 */
-        while (*msg++)
-            ;
-    }
-
-    LOGV("event { '%s', '%s', '%s', '%s', '%s', '%s' }\n",
-         uevent->action, uevent->path, uevent->subsystem,
-         uevent->ps_name, uevent->ps_type, uevent->ps_online);
-}
-
-static void process_ps_uevent(struct charger *charger, struct uevent *uevent)
-{
-    int online;
-    char ps_type[32];
-    struct power_supply *supply = NULL;
-    int i;
-    bool was_online = false;
-    bool battery = false;
-
-    if (uevent->ps_type[0] == '\0') {
-        char *path;
-        int ret;
-
-        if (uevent->path[0] == '\0')
-            return;
-        ret = asprintf(&path, "/sys/%s/type", uevent->path);
-        if (ret <= 0)
-            return;
-        ret = read_file(path, ps_type, sizeof(ps_type));
-        free(path);
-        if (ret < 0)
-            return;
-    } else {
-        strlcpy(ps_type, uevent->ps_type, sizeof(ps_type));
-    }
-
-    if (!strncmp(ps_type, "Battery", 7))
-        battery = true;
-
-    online = atoi(uevent->ps_online);
-    supply = find_supply(charger, uevent->ps_name);
-    if (supply) {
-        was_online = supply->online;
-        supply->online = online;
-    }
-
-    if (!strcmp(uevent->action, "add")) {
-        if (!supply) {
-            supply = add_supply(charger, uevent->ps_name, ps_type, uevent->path,
-                                online);
-            if (!supply) {
-                LOGE("cannot add supply '%s' (%s %d)\n", uevent->ps_name,
-                     uevent->ps_type, online);
-                return;
-            }
-            /* only pick up the first battery for now */
-            if (battery && !charger->battery)
-                charger->battery = supply;
-        } else {
-            LOGE("supply '%s' already exists..\n", uevent->ps_name);
-        }
-    } else if (!strcmp(uevent->action, "remove")) {
-        if (supply) {
-            if (charger->battery == supply)
-                charger->battery = NULL;
-            remove_supply(charger, supply);
-            supply = NULL;
-        }
-    } else if (!strcmp(uevent->action, "change")) {
-        if (!supply) {
-            LOGE("power supply '%s' not found ('%s' %d)\n",
-                 uevent->ps_name, ps_type, online);
-            return;
-        }
-    } else {
-        return;
-    }
-
-    /* allow battery to be managed in the supply list but make it not
-     * contribute to online power supplies. */
-    if (!battery) {
-        if (was_online && !online)
-            charger->num_supplies_online--;
-        else if (supply && !was_online && online)
-            charger->num_supplies_online++;
-    }
-
-    LOGI("power supply %s (%s) %s (action=%s num_online=%d num_supplies=%d)\n",
-         uevent->ps_name, ps_type, battery ? "" : online ? "online" : "offline",
-         uevent->action, charger->num_supplies_online, charger->num_supplies);
-}
-
-static void process_uevent(struct charger *charger, struct uevent *uevent)
-{
-    if (!strcmp(uevent->subsystem, "power_supply"))
-        process_ps_uevent(charger, uevent);
-}
-
-#define UEVENT_MSG_LEN  1024
-static int handle_uevent_fd(struct charger *charger, int fd)
-{
-    char msg[UEVENT_MSG_LEN+2];
-    int n;
-
-    if (fd < 0)
-        return -1;
-
-    while (true) {
-        struct uevent uevent;
-
-        n = uevent_kernel_multicast_recv(fd, msg, UEVENT_MSG_LEN);
-        if (n <= 0)
-            break;
-        if (n >= UEVENT_MSG_LEN)   /* overflow -- discard */
-            continue;
-
-        msg[n] = '\0';
-        msg[n+1] = '\0';
-
-        parse_uevent(msg, &uevent);
-        process_uevent(charger, &uevent);
-    }
-
-    return 0;
-}
-
-static int uevent_callback(int fd, short revents, void *data)
-{
-    struct charger *charger = data;
-
-    if (!(revents & POLLIN))
-        return -1;
-    return handle_uevent_fd(charger, fd);
-}
-
-/* force the kernel to regenerate the change events for the existing
- * devices, if valid */
-static void do_coldboot(struct charger *charger, DIR *d, const char *event,
-                        bool follow_links, int max_depth)
-{
-    struct dirent *de;
-    int dfd, fd;
-
-    dfd = dirfd(d);
-
-    fd = openat(dfd, "uevent", O_WRONLY);
-    if (fd >= 0) {
-        write(fd, event, strlen(event));
-        close(fd);
-        handle_uevent_fd(charger, charger->uevent_fd);
-    }
-
-    while ((de = readdir(d)) && max_depth > 0) {
-        DIR *d2;
-
-        LOGV("looking at '%s'\n", de->d_name);
-
-        if ((de->d_type != DT_DIR && !(de->d_type == DT_LNK && follow_links)) ||
-           de->d_name[0] == '.') {
-            LOGV("skipping '%s' type %d (depth=%d follow=%d)\n",
-                 de->d_name, de->d_type, max_depth, follow_links);
-            continue;
-        }
-        LOGV("can descend into '%s'\n", de->d_name);
-
-        fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY);
-        if (fd < 0) {
-            LOGE("cannot openat %d '%s' (%d: %s)\n", dfd, de->d_name,
-                 errno, strerror(errno));
-            continue;
-        }
-
-        d2 = fdopendir(fd);
-        if (d2 == 0)
-            close(fd);
-        else {
-            LOGV("opened '%s'\n", de->d_name);
-            do_coldboot(charger, d2, event, follow_links, max_depth - 1);
-            closedir(d2);
-        }
-    }
-}
-
-static void coldboot(struct charger *charger, const char *path,
-                     const char *event)
-{
-    char str[256];
-
-    LOGV("doing coldboot '%s' in '%s'\n", event, path);
-    DIR *d = opendir(path);
-    if (d) {
-        snprintf(str, sizeof(str), "%s\n", event);
-        do_coldboot(charger, d, str, true, 1);
-        closedir(d);
-    }
-}
-
-static int draw_text(const char *str, int x, int y)
-{
-    int str_len_px = gr_measure(str);
-
-    if (x < 0)
-        x = (gr_fb_width() - str_len_px) / 2;
-    if (y < 0)
-        y = (gr_fb_height() - char_height) / 2;
-    gr_text(x, y, str, 0);
-
-    return y + char_height;
-}
-
-static void android_green(void)
-{
-    gr_color(0xa4, 0xc6, 0x39, 255);
-}
-
-/* returns the last y-offset of where the surface ends */
-static int draw_surface_centered(struct charger *charger, gr_surface surface)
-{
-    int w;
-    int h;
-    int x;
-    int y;
-
-    w = gr_get_width(surface);
-    h = gr_get_height(surface);
-    x = (gr_fb_width() - w) / 2 ;
-    y = (gr_fb_height() - h) / 2 ;
-
-    LOGV("drawing surface %dx%d+%d+%d\n", w, h, x, y);
-    gr_blit(surface, 0, 0, w, h, x, y);
-    return y + h;
-}
-
-static void draw_unknown(struct charger *charger)
-{
-    int y;
-    if (charger->surf_unknown) {
-        draw_surface_centered(charger, charger->surf_unknown);
-    } else {
-        android_green();
-        y = draw_text("Charging!", -1, -1);
-        draw_text("?\?/100", -1, y + 25);
-    }
-}
-
-static void draw_battery(struct charger *charger)
-{
-    struct animation *batt_anim = charger->batt_anim;
-    struct frame *frame = &batt_anim->frames[batt_anim->cur_frame];
-
-    if (batt_anim->num_frames != 0) {
-        draw_surface_centered(charger, frame->surface);
-        LOGV("drawing frame #%d min_cap=%d time=%d\n",
-             batt_anim->cur_frame, frame->min_capacity,
-             frame->disp_time);
-    }
-}
-
-static void redraw_screen(struct charger *charger)
-{
-    struct animation *batt_anim = charger->batt_anim;
-
-    clear_screen();
-
-    /* try to display *something* */
-    if (batt_anim->capacity < 0 || batt_anim->num_frames == 0)
-        draw_unknown(charger);
-    else
-        draw_battery(charger);
-    gr_flip();
-}
-
-static void kick_animation(struct animation *anim)
-{
-    anim->run = true;
-}
-
-static void reset_animation(struct animation *anim)
-{
-    anim->cur_cycle = 0;
-    anim->cur_frame = 0;
-    anim->run = false;
-}
-
-static void update_screen_state(struct charger *charger, int64_t now)
-{
-    struct animation *batt_anim = charger->batt_anim;
-    int cur_frame;
-    int disp_time;
-
-    if (!batt_anim->run || now < charger->next_screen_transition)
-        return;
-
-    /* animation is over, blank screen and leave */
-    if (batt_anim->cur_cycle == batt_anim->num_cycles) {
-        reset_animation(batt_anim);
-        charger->next_screen_transition = -1;
-        gr_fb_blank(true);
-        LOGV("[%lld] animation done\n", now);
-        if (charger->num_supplies_online > 0)
-            request_suspend(true);
-        return;
-    }
-
-    disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time;
-
-    /* animation starting, set up the animation */
-    if (batt_anim->cur_frame == 0) {
-        int batt_cap;
-        int ret;
-
-        LOGV("[%lld] animation starting\n", now);
-        batt_cap = get_battery_capacity(charger);
-        if (batt_cap >= 0 && batt_anim->num_frames != 0) {
-            int i;
-
-            /* find first frame given current capacity */
-            for (i = 1; i < batt_anim->num_frames; i++) {
-                if (batt_cap < batt_anim->frames[i].min_capacity)
-                    break;
-            }
-            batt_anim->cur_frame = i - 1;
-
-            /* show the first frame for twice as long */
-            disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time * 2;
-        }
-
-        batt_anim->capacity = batt_cap;
-    }
-
-    /* unblank the screen  on first cycle */
-    if (batt_anim->cur_cycle == 0)
-        gr_fb_blank(false);
-
-    /* draw the new frame (@ cur_frame) */
-    redraw_screen(charger);
-
-    /* if we don't have anim frames, we only have one image, so just bump
-     * the cycle counter and exit
-     */
-    if (batt_anim->num_frames == 0 || batt_anim->capacity < 0) {
-        LOGV("[%lld] animation missing or unknown battery status\n", now);
-        charger->next_screen_transition = now + BATTERY_UNKNOWN_TIME;
-        batt_anim->cur_cycle++;
-        return;
-    }
-
-    /* schedule next screen transition */
-    charger->next_screen_transition = now + disp_time;
-
-    /* advance frame cntr to the next valid frame
-     * if necessary, advance cycle cntr, and reset frame cntr
-     */
-    batt_anim->cur_frame++;
-
-    /* if the frame is used for level-only, that is only show it when it's
-     * the current level, skip it during the animation.
-     */
-    while (batt_anim->cur_frame < batt_anim->num_frames &&
-           batt_anim->frames[batt_anim->cur_frame].level_only)
-        batt_anim->cur_frame++;
-    if (batt_anim->cur_frame >= batt_anim->num_frames) {
-        batt_anim->cur_cycle++;
-        batt_anim->cur_frame = 0;
-
-        /* don't reset the cycle counter, since we use that as a signal
-         * in a test above to check if animation is over
-         */
-    }
-}
-
-static int set_key_callback(int code, int value, void *data)
-{
-    struct charger *charger = data;
-    int64_t now = curr_time_ms();
-    int down = !!value;
-
-    if (code > KEY_MAX)
-        return -1;
-
-    /* ignore events that don't modify our state */
-    if (charger->keys[code].down == down)
-        return 0;
-
-    /* only record the down even timestamp, as the amount
-     * of time the key spent not being pressed is not useful */
-    if (down)
-        charger->keys[code].timestamp = now;
-    charger->keys[code].down = down;
-    charger->keys[code].pending = true;
-    if (down) {
-        LOGV("[%lld] key[%d] down\n", now, code);
-    } else {
-        int64_t duration = now - charger->keys[code].timestamp;
-        int64_t secs = duration / 1000;
-        int64_t msecs = duration - secs * 1000;
-        LOGV("[%lld] key[%d] up (was down for %lld.%lldsec)\n", now,
-            code, secs, msecs);
-    }
-
-    return 0;
-}
-
-static void update_input_state(struct charger *charger,
-                               struct input_event *ev)
-{
-    if (ev->type != EV_KEY)
-        return;
-    set_key_callback(ev->code, ev->value, charger);
-}
-
-static void set_next_key_check(struct charger *charger,
-                               struct key_state *key,
-                               int64_t timeout)
-{
-    int64_t then = key->timestamp + timeout;
-
-    if (charger->next_key_check == -1 || then < charger->next_key_check)
-        charger->next_key_check = then;
-}
-
-static void process_key(struct charger *charger, int code, int64_t now)
-{
-    struct key_state *key = &charger->keys[code];
-    int64_t next_key_check;
-
-    if (code == KEY_POWER) {
-        if (key->down) {
-            int64_t reboot_timeout = key->timestamp + POWER_ON_KEY_TIME;
-            if (now >= reboot_timeout) {
-                /* We do not currently support booting from charger mode on
-                   all devices. Check the property and continue booting or reboot
-                   accordingly. */
-                if (property_get_bool("ro.enable_boot_charger_mode", false)) {
-                    LOGI("[%lld] booting from charger mode\n", now);
-                    property_set("sys.boot_from_charger_mode", "1");
-                } else {
-                    LOGI("[%lld] rebooting\n", now);
-                    android_reboot(ANDROID_RB_RESTART, 0, 0);
-                }
-            } else {
-                /* if the key is pressed but timeout hasn't expired,
-                 * make sure we wake up at the right-ish time to check
-                 */
-                set_next_key_check(charger, key, POWER_ON_KEY_TIME);
-            }
-        } else {
-            /* if the power key got released, force screen state cycle */
-            if (key->pending) {
-                request_suspend(false);
-                kick_animation(charger->batt_anim);
-            }
-        }
-    }
-
-    key->pending = false;
-}
-
-static void handle_input_state(struct charger *charger, int64_t now)
-{
-    process_key(charger, KEY_POWER, now);
-
-    if (charger->next_key_check != -1 && now > charger->next_key_check)
-        charger->next_key_check = -1;
-}
-
-static void handle_power_supply_state(struct charger *charger, int64_t now)
-{
-    if (charger->num_supplies_online == 0) {
-        request_suspend(false);
-        if (charger->next_pwr_check == -1) {
-            charger->next_pwr_check = now + UNPLUGGED_SHUTDOWN_TIME;
-            LOGI("[%lld] device unplugged: shutting down in %lld (@ %lld)\n",
-                 now, UNPLUGGED_SHUTDOWN_TIME, charger->next_pwr_check);
-        } else if (now >= charger->next_pwr_check) {
-            LOGI("[%lld] shutting down\n", now);
-            android_reboot(ANDROID_RB_POWEROFF, 0, 0);
-        } else {
-            /* otherwise we already have a shutdown timer scheduled */
-        }
-    } else {
-        /* online supply present, reset shutdown timer if set */
-        if (charger->next_pwr_check != -1) {
-            LOGI("[%lld] device plugged in: shutdown cancelled\n", now);
-            kick_animation(charger->batt_anim);
-        }
-        charger->next_pwr_check = -1;
-    }
-}
-
-static void wait_next_event(struct charger *charger, int64_t now)
-{
-    int64_t next_event = INT64_MAX;
-    int64_t timeout;
-    struct input_event ev;
-    int ret;
-
-    LOGV("[%lld] next screen: %lld next key: %lld next pwr: %lld\n", now,
-         charger->next_screen_transition, charger->next_key_check,
-         charger->next_pwr_check);
-
-    if (charger->next_screen_transition != -1)
-        next_event = charger->next_screen_transition;
-    if (charger->next_key_check != -1 && charger->next_key_check < next_event)
-        next_event = charger->next_key_check;
-    if (charger->next_pwr_check != -1 && charger->next_pwr_check < next_event)
-        next_event = charger->next_pwr_check;
-
-    if (next_event != -1 && next_event != INT64_MAX)
-        timeout = max(0, next_event - now);
-    else
-        timeout = -1;
-    LOGV("[%lld] blocking (%lld)\n", now, timeout);
-    ret = ev_wait((int)timeout);
-    if (!ret)
-        ev_dispatch();
-}
-
-static int input_callback(int fd, short revents, void *data)
-{
-    struct charger *charger = data;
-    struct input_event ev;
-    int ret;
-
-    ret = ev_get_input(fd, revents, &ev);
-    if (ret)
-        return -1;
-    update_input_state(charger, &ev);
-    return 0;
-}
-
-static void event_loop(struct charger *charger)
-{
-    int ret;
-
-    while (true) {
-        int64_t now = curr_time_ms();
-
-        LOGV("[%lld] event_loop()\n", now);
-        handle_input_state(charger, now);
-        handle_power_supply_state(charger, now);
-
-        /* do screen update last in case any of the above want to start
-         * screen transitions (animations, etc)
-         */
-        update_screen_state(charger, now);
-
-        wait_next_event(charger, now);
-    }
-}
-
-int main(int argc, char **argv)
-{
-    int ret;
-    struct charger *charger = &charger_state;
-    int64_t now = curr_time_ms() - 1;
-    int fd;
-    int i;
-
-    list_init(&charger->supplies);
-
-    klog_init();
-    klog_set_level(CHARGER_KLOG_LEVEL);
-
-    dump_last_kmsg();
-
-    LOGI("--------------- STARTING CHARGER MODE ---------------\n");
-
-    gr_init();
-    gr_font_size(&char_width, &char_height);
-
-    ev_init(input_callback, charger);
-
-    fd = uevent_open_socket(64*1024, true);
-    if (fd >= 0) {
-        fcntl(fd, F_SETFL, O_NONBLOCK);
-        ev_add_fd(fd, uevent_callback, charger);
-    }
-    charger->uevent_fd = fd;
-    coldboot(charger, "/sys/class/power_supply", "add");
-
-    ret = res_create_display_surface("charger/battery_fail", &charger->surf_unknown);
-    if (ret < 0) {
-        LOGE("Cannot load battery_fail image\n");
-        charger->surf_unknown = NULL;
-    }
-
-    charger->batt_anim = &battery_animation;
-
-    gr_surface* scale_frames;
-    int scale_count;
-    ret = res_create_multi_display_surface("charger/battery_scale", &scale_count, &scale_frames);
-    if (ret < 0) {
-        LOGE("Cannot load battery_scale image\n");
-        charger->batt_anim->num_frames = 0;
-        charger->batt_anim->num_cycles = 1;
-    } else if (scale_count != charger->batt_anim->num_frames) {
-        LOGE("battery_scale image has unexpected frame count (%d, expected %d)\n",
-             scale_count, charger->batt_anim->num_frames);
-        charger->batt_anim->num_frames = 0;
-        charger->batt_anim->num_cycles = 1;
-    } else {
-        for (i = 0; i < charger->batt_anim->num_frames; i++) {
-            charger->batt_anim->frames[i].surface = scale_frames[i];
-        }
-    }
-
-    ev_sync_key_state(set_key_callback, charger);
-
-#ifndef CHARGER_DISABLE_INIT_BLANK
-    gr_fb_blank(true);
-#endif
-
-    charger->next_screen_transition = now - 1;
-    charger->next_key_check = -1;
-    charger->next_pwr_check = -1;
-    reset_animation(charger->batt_anim);
-    kick_animation(charger->batt_anim);
-
-    event_loop(charger);
-
-    return 0;
-}
diff --git a/debuggerd/arm/machine.cpp b/debuggerd/arm/machine.cpp
index 8270066..50e78c5 100644
--- a/debuggerd/arm/machine.cpp
+++ b/debuggerd/arm/machine.cpp
@@ -82,13 +82,13 @@
 
   user_vfp vfp_regs;
   if (ptrace(PTRACE_GETVFPREGS, tid, 0, &vfp_regs)) {
-    _LOG(log, logtype::REGISTERS, "cannot get registers: %s\n", strerror(errno));
+    _LOG(log, logtype::FP_REGISTERS, "cannot get FP registers: %s\n", strerror(errno));
     return;
   }
 
   for (size_t i = 0; i < 32; i += 2) {
-    _LOG(log, logtype::REGISTERS, "    d%-2d %016llx  d%-2d %016llx\n",
+    _LOG(log, logtype::FP_REGISTERS, "    d%-2d %016llx  d%-2d %016llx\n",
          i, vfp_regs.fpregs[i], i+1, vfp_regs.fpregs[i+1]);
   }
-  _LOG(log, logtype::REGISTERS, "    scr %08lx\n", vfp_regs.fpscr);
+  _LOG(log, logtype::FP_REGISTERS, "    scr %08lx\n", vfp_regs.fpscr);
 }
diff --git a/debuggerd/arm64/machine.cpp b/debuggerd/arm64/machine.cpp
index ec664bd..8b17d53 100644
--- a/debuggerd/arm64/machine.cpp
+++ b/debuggerd/arm64/machine.cpp
@@ -15,17 +15,14 @@
  * limitations under the License.
  */
 
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <stdio.h>
+#include <elf.h>
 #include <errno.h>
+#include <inttypes.h>
+#include <string.h>
 #include <sys/types.h>
 #include <sys/ptrace.h>
 #include <sys/user.h>
 #include <sys/uio.h>
-#include <linux/elf.h>
 
 #include "../utility.h"
 #include "../machine.h"
@@ -79,19 +76,18 @@
 
   for (int i = 0; i < 28; i += 4) {
     _LOG(log, logtype::REGISTERS,
-         "    x%-2d  %016lx  x%-2d  %016lx  x%-2d  %016lx  x%-2d  %016lx\n",
-         i, (uint64_t)r.regs[i],
-         i+1, (uint64_t)r.regs[i+1],
-         i+2, (uint64_t)r.regs[i+2],
-         i+3, (uint64_t)r.regs[i+3]);
+         "    x%-2d  %016llx  x%-2d  %016llx  x%-2d  %016llx  x%-2d  %016llx\n",
+         i, r.regs[i],
+         i+1, r.regs[i+1],
+         i+2, r.regs[i+2],
+         i+3, r.regs[i+3]);
   }
 
-  _LOG(log, logtype::REGISTERS, "    x28  %016lx  x29  %016lx  x30  %016lx\n",
-       (uint64_t)r.regs[28], (uint64_t)r.regs[29], (uint64_t)r.regs[30]);
+  _LOG(log, logtype::REGISTERS, "    x28  %016llx  x29  %016llx  x30  %016llx\n",
+       r.regs[28], r.regs[29], r.regs[30]);
 
-  _LOG(log, logtype::REGISTERS, "    sp   %016lx  pc   %016lx\n",
-       (uint64_t)r.sp, (uint64_t)r.pc);
-
+  _LOG(log, logtype::REGISTERS, "    sp   %016llx  pc   %016llx  pstate %016llx\n",
+       r.sp, r.pc, r.pstate);
 
   struct user_fpsimd_state f;
   io.iov_base = &f;
@@ -102,11 +98,15 @@
     return;
   }
 
-  for (int i = 0; i < 32; i += 4) {
-    _LOG(log, logtype::REGISTERS, "    v%-2d  %016lx  v%-2d  %016lx  v%-2d  %016lx  v%-2d  %016lx\n",
-         i, (uint64_t)f.vregs[i],
-         i+1, (uint64_t)f.vregs[i+1],
-         i+2, (uint64_t)f.vregs[i+2],
-         i+3, (uint64_t)f.vregs[i+3]);
+  for (int i = 0; i < 32; i += 2) {
+    _LOG(log, logtype::FP_REGISTERS,
+         "    v%-2d  %016" PRIx64 "%016" PRIx64 "  v%-2d  %016" PRIx64 "%016" PRIx64 "\n",
+         i,
+         static_cast<uint64_t>(f.vregs[i] >> 64),
+         static_cast<uint64_t>(f.vregs[i]),
+         i+1,
+         static_cast<uint64_t>(f.vregs[i+1] >> 64),
+         static_cast<uint64_t>(f.vregs[i+1]));
   }
+  _LOG(log, logtype::FP_REGISTERS, "    fpsr %08x  fpcr %08x\n", f.fpsr, f.fpcr);
 }
diff --git a/debuggerd/backtrace.cpp b/debuggerd/backtrace.cpp
index c4a2143..e49ef9b 100644
--- a/debuggerd/backtrace.cpp
+++ b/debuggerd/backtrace.cpp
@@ -49,13 +49,13 @@
   struct tm tm;
   localtime_r(&t, &tm);
   char timestr[64];
-  _LOG(log, logtype::BACKTRACE, "\n\nABI: '%s'\n", ABI_STRING);
   strftime(timestr, sizeof(timestr), "%F %T", &tm);
-  _LOG(log, logtype::BACKTRACE, "\n----- pid %d at %s -----\n", pid, timestr);
+  _LOG(log, logtype::BACKTRACE, "\n\n----- pid %d at %s -----\n", pid, timestr);
 
   if (procname) {
     _LOG(log, logtype::BACKTRACE, "Cmd line: %s\n", procname);
   }
+  _LOG(log, logtype::BACKTRACE, "ABI: '%s'\n", ABI_STRING);
 }
 
 static void dump_process_footer(log_t* log, pid_t pid) {
diff --git a/debuggerd/crasher.c b/debuggerd/crasher.c
index 9df3c64..d315ee5 100644
--- a/debuggerd/crasher.c
+++ b/debuggerd/crasher.c
@@ -141,11 +141,14 @@
     } else if (!strcmp(arg, "assert")) {
         __assert("some_file.c", 123, "false");
     } else if (!strcmp(arg, "assert2")) {
-      __assert2("some_file.c", 123, "some_function", "false");
+        __assert2("some_file.c", 123, "some_function", "false");
     } else if (!strcmp(arg, "LOG_ALWAYS_FATAL")) {
         LOG_ALWAYS_FATAL("hello %s", "world");
     } else if (!strcmp(arg, "LOG_ALWAYS_FATAL_IF")) {
         LOG_ALWAYS_FATAL_IF(true, "hello %s", "world");
+    } else if (!strcmp(arg, "SIGFPE")) {
+        raise(SIGFPE);
+        return EXIT_SUCCESS;
     } else if (!strcmp(arg, "SIGPIPE")) {
         int pipe_fds[2];
         pipe(pipe_fds);
@@ -177,6 +180,7 @@
     fprintf(stderr, "  assert2               call assert() with a function\n");
     fprintf(stderr, "  LOG_ALWAYS_FATAL      call LOG_ALWAYS_FATAL\n");
     fprintf(stderr, "  LOG_ALWAYS_FATAL_IF   call LOG_ALWAYS_FATAL\n");
+    fprintf(stderr, "  SIGFPE                cause a SIGFPE\n");
     fprintf(stderr, "  SIGPIPE               cause a SIGPIPE\n");
     fprintf(stderr, "  SIGSEGV               cause a SIGSEGV at address 0x0 (synonym: crash)\n");
     fprintf(stderr, "  SIGSEGV-non-null      cause a SIGSEGV at a non-zero address\n");
diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp
old mode 100755
new mode 100644
index f41166b..a7e1524
--- a/debuggerd/tombstone.cpp
+++ b/debuggerd/tombstone.cpp
@@ -64,6 +64,7 @@
     case SIGFPE:
     case SIGILL:
     case SIGSEGV:
+    case SIGTRAP:
       return true;
     default:
       return false;
@@ -210,6 +211,12 @@
       }
     }
   }
+  // Blacklist logd, logd.reader, logd.writer, logd.auditd, logd.control ...
+  static const char logd[] = "logd";
+  if (!strncmp(threadname, logd, sizeof(logd) - 1)
+      && (!threadname[sizeof(logd) - 1] || (threadname[sizeof(logd) - 1] == '.'))) {
+    log->should_retrieve_logcat = false;
+  }
 
   char procnamebuf[1024];
   char* procname = NULL;
@@ -344,16 +351,12 @@
     return;
   }
 
-  bool is_running = (si.si_code == SI_USER);
+  bool has_fault_address = signal_has_si_addr(si.si_signo);
   uintptr_t addr = reinterpret_cast<uintptr_t>(si.si_addr);
-  addr &= ~0xfff;     // round to 4K page boundary
-  if (!is_running && addr == 0) {    // null-pointer deref
-    return;
-  }
 
-  _LOG(log, logtype::MAPS, "\nmemory map: %s\n", is_running? "" : "(fault address prefixed with --->)");
+  _LOG(log, logtype::MAPS, "\nmemory map: %s\n", has_fault_address ? "(fault address prefixed with --->)" : "");
 
-  if(!is_running && (addr < map->begin()->start)) {
+  if (has_fault_address && (addr < map->begin()->start)) {
     _LOG(log, logtype::MAPS, "--->Fault address falls at %" PRIPTR " before any mapped regions\n", addr);
   }
 
@@ -363,10 +366,10 @@
       _LOG(log, logtype::MAPS, "--->Fault address falls at %" PRIPTR " between mapped regions\n", addr);
     }
     prev = it;
-    bool in_map = !is_running && (addr >= (*it).start) && (addr < (*it).end);
+    bool in_map = has_fault_address && (addr >= (*it).start) && (addr < (*it).end);
     dump_map(log, &*it, in_map);
   }
-  if (!is_running && (addr >= (*prev).end)) {
+  if (has_fault_address && (addr >= (*prev).end)) {
     _LOG(log, logtype::MAPS, "--->Fault address falls at %" PRIPTR " after any mapped regions\n", addr);
   }
 }
@@ -450,6 +453,10 @@
   bool first = true;
   struct logger_list* logger_list;
 
+  if (!log->should_retrieve_logcat) {
+    return;
+  }
+
   logger_list = android_logger_list_open(
       android_name_to_log_id(filename), O_RDONLY | O_NONBLOCK, tail, pid);
 
@@ -674,7 +681,7 @@
     if (errno != ENOENT)
       continue;
 
-    *fd = open(path, O_CREAT | O_EXCL | O_WRONLY, 0600);
+    *fd = open(path, O_CREAT | O_EXCL | O_WRONLY | O_NOFOLLOW | O_CLOEXEC, 0600);
     if (*fd < 0)
       continue;   // raced ?
 
@@ -689,7 +696,7 @@
 
   // we didn't find an available file, so we clobber the oldest one
   snprintf(path, sizeof(path), TOMBSTONE_TEMPLATE, oldest);
-  *fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
+  *fd = open(path, O_CREAT | O_TRUNC | O_WRONLY | O_NOFOLLOW | O_CLOEXEC, 0600);
   if (*fd < 0) {
     ALOGE("failed to open tombstone file '%s': %s\n", path, strerror(errno));
     return NULL;
diff --git a/debuggerd/utility.cpp b/debuggerd/utility.cpp
index a163344..9a30fe3 100644
--- a/debuggerd/utility.cpp
+++ b/debuggerd/utility.cpp
@@ -59,6 +59,8 @@
 void _LOG(log_t* log, enum logtype ltype, const char* fmt, ...) {
   bool write_to_tombstone = (log->tfd != -1);
   bool write_to_logcat = is_allowed_in_logcat(ltype)
+                      && log->crashed_tid != -1
+                      && log->current_tid != -1
                       && (log->crashed_tid == log->current_tid);
   bool write_to_activitymanager = (log->amfd != -1);
 
diff --git a/debuggerd/utility.h b/debuggerd/utility.h
index f2e2d29..82413b8 100644
--- a/debuggerd/utility.h
+++ b/debuggerd/utility.h
@@ -2,16 +2,16 @@
 **
 ** Copyright 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 
+** 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 
+**     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 
+** 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.
 */
 
@@ -37,7 +37,7 @@
 #endif
 
 
-typedef struct {
+struct log_t{
     /* tombstone file descriptor */
     int tfd;
     /* Activity Manager socket file descriptor */
@@ -46,7 +46,12 @@
     pid_t crashed_tid;
     // The tid of the thread we are currently working with.
     pid_t current_tid;
-} log_t;
+    // logd daemon crash, can block asking for logcat data, allow suppression.
+    bool should_retrieve_logcat;
+
+    log_t()
+        : tfd(-1), amfd(-1), crashed_tid(-1), current_tid(-1), should_retrieve_logcat(true) {}
+};
 
 // List of types of logs to simplify the logging decision in _LOG
 enum logtype {
@@ -54,6 +59,7 @@
   HEADER,
   THREAD,
   REGISTERS,
+  FP_REGISTERS,
   BACKTRACE,
   MAPS,
   MEMORY,
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index 73794a0..e11691f 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -17,7 +17,8 @@
 include $(CLEAR_VARS)
 
 LOCAL_C_INCLUDES := $(LOCAL_PATH)/../mkbootimg \
-  $(LOCAL_PATH)/../../extras/ext4_utils
+  $(LOCAL_PATH)/../../extras/ext4_utils \
+  $(LOCAL_PATH)/../../extras/f2fs_utils
 LOCAL_SRC_FILES := protocol.c engine.c bootimg.c fastboot.c util.c fs.c
 LOCAL_MODULE := fastboot
 LOCAL_MODULE_TAGS := debug
@@ -39,13 +40,11 @@
   ifneq ($(strip $(USE_CYGWIN)),)
     # Pure cygwin case
     LOCAL_LDLIBS += -lpthread
-    LOCAL_C_INCLUDES += /usr/include/w32api/ddk
   endif
   ifneq ($(strip $(USE_MINGW)),)
     # MinGW under Linux case
     LOCAL_LDLIBS += -lws2_32
     USE_SYSDEPS_WIN32 := 1
-    LOCAL_C_INCLUDES += /usr/i586-mingw32msvc/include/ddk
   endif
   LOCAL_C_INCLUDES += development/host/windows/usb/api
 endif
@@ -62,10 +61,24 @@
 LOCAL_STATIC_LIBRARIES += libselinux
 endif # HOST_OS != windows
 
+ifeq ($(HOST_OS),linux)
+# libf2fs_dlutils_host will dlopen("libf2fs_fmt_host_dyn")
+LOCAL_CFLAGS += -DUSE_F2FS
+LOCAL_LDFLAGS += -ldl -rdynamic -Wl,-rpath,.
+LOCAL_REQUIRED_MODULES := libf2fs_fmt_host_dyn
+# The following libf2fs_* are from system/extras/f2fs_utils,
+# and do not use code in external/f2fs-tools.
+LOCAL_STATIC_LIBRARIES += libf2fs_utils_host libf2fs_ioutils_host libf2fs_dlutils_host
+endif
+
 include $(BUILD_HOST_EXECUTABLE)
 
-
-$(call dist-for-goals,dist_files sdk,$(LOCAL_BUILT_MODULE))
+my_dist_files := $(LOCAL_BUILT_MODULE)
+ifeq ($(HOST_OS),linux)
+my_dist_files += $(HOST_LIBRARY_PATH)/libf2fs_fmt_host_dyn$(HOST_SHLIB_SUFFIX)
+endif
+$(call dist-for-goals,dist_files sdk,$(my_dist_files))
+my_dist_files :=
 
 
 ifeq ($(HOST_OS),linux)
diff --git a/fastboot/fastboot.c b/fastboot/fastboot.c
index 266d0b5..43d05aa 100644
--- a/fastboot/fastboot.c
+++ b/fastboot/fastboot.c
@@ -99,11 +99,11 @@
     char sig_name[13];
     char part_name[9];
     bool is_optional;
-} images[4] = {
+} images[] = {
     {"boot.img", "boot.sig", "boot", false},
     {"recovery.img", "recovery.sig", "recovery", true},
     {"system.img", "system.sig", "system", false},
-    {"tos.img", "tos.sig", "tos", true},
+    {"vendor.img", "vendor.sig", "vendor", true},
 };
 
 void get_my_path(char *path);
@@ -120,8 +120,8 @@
         fn = "recovery.img";
     } else if(!strcmp(item,"system")) {
         fn = "system.img";
-    } else if(!strcmp(item,"tos")) {
-        fn = "tos.img";
+    } else if(!strcmp(item,"vendor")) {
+        fn = "vendor.img";
     } else if(!strcmp(item,"userdata")) {
         fn = "userdata.img";
     } else if(!strcmp(item,"cache")) {
@@ -287,16 +287,17 @@
             "\n"
             "commands:\n"
             "  update <filename>                        reflash device from update.zip\n"
-            "  flashall                                 flash boot, system, and if found,\n"
-            "                                           recovery, tos\n"
+            "  flashall                                 flash boot, system, vendor and if found,\n"
+            "                                           recovery\n"
             "  flash <partition> [ <filename> ]         write a file to a flash partition\n"
             "  erase <partition>                        erase a flash partition\n"
             "  format[:[<fs type>][:[<size>]] <partition> format a flash partition.\n"
             "                                           Can override the fs type and/or\n"
             "                                           size the bootloader reports.\n"
             "  getvar <variable>                        display a bootloader variable\n"
-            "  boot <kernel> [ <ramdisk> ]              download and boot kernel\n"
-            "  flash:raw boot <kernel> [ <ramdisk> ]    create bootimage and flash it\n"
+            "  boot <kernel> [ <ramdisk> [ <second> ] ] download and boot kernel\n"
+            "  flash:raw boot <kernel> [ <ramdisk> [ <second> ] ] create bootimage and \n"
+            "                                           flash it\n"
             "  devices                                  list all connected devices\n"
             "  continue                                 continue with autoboot\n"
             "  reboot                                   reboot device normally\n"
@@ -324,10 +325,11 @@
 }
 
 void *load_bootable_image(const char *kernel, const char *ramdisk,
-                          unsigned *sz, const char *cmdline)
+                          const char *secondstage, unsigned *sz,
+                          const char *cmdline)
 {
-    void *kdata = 0, *rdata = 0;
-    unsigned ksize = 0, rsize = 0;
+    void *kdata = 0, *rdata = 0, *sdata = 0;
+    unsigned ksize = 0, rsize = 0, ssize = 0;
     void *bdata;
     unsigned bsize;
 
@@ -363,10 +365,18 @@
         }
     }
 
+    if (secondstage) {
+        sdata = load_file(secondstage, &ssize);
+        if(sdata == 0) {
+            fprintf(stderr,"cannot load '%s': %s\n", secondstage, strerror(errno));
+            return  0;
+        }
+    }
+
     fprintf(stderr,"creating boot image...\n");
     bdata = mkbootimg(kdata, ksize, kernel_offset,
                       rdata, rsize, ramdisk_offset,
-                      0, 0, second_offset,
+                      sdata, ssize, second_offset,
                       page_size, base_addr, tags_offset, &bsize);
     if(bdata == 0) {
         fprintf(stderr,"failed to create boot.img\n");
@@ -1144,6 +1154,7 @@
         } else if(!strcmp(*argv, "boot")) {
             char *kname = 0;
             char *rname = 0;
+            char *sname = 0;
             skip(1);
             if (argc > 0) {
                 kname = argv[0];
@@ -1153,7 +1164,11 @@
                 rname = argv[0];
                 skip(1);
             }
-            data = load_bootable_image(kname, rname, &sz, cmdline);
+            if (argc > 0) {
+                sname = argv[0];
+                skip(1);
+            }
+            data = load_bootable_image(kname, rname, sname, &sz, cmdline);
             if (data == 0) return 1;
             fb_queue_download("boot.img", data, sz);
             fb_queue_command("boot", "booting");
@@ -1177,14 +1192,18 @@
             char *pname = argv[1];
             char *kname = argv[2];
             char *rname = 0;
+            char *sname = 0;
             require(3);
-            if(argc > 3) {
-                rname = argv[3];
-                skip(4);
-            } else {
-                skip(3);
+            skip(3);
+            if (argc > 0) {
+                rname = argv[0];
+                skip(1);
             }
-            data = load_bootable_image(kname, rname, &sz, cmdline);
+            if (argc > 0) {
+                sname = argv[0];
+                skip(1);
+            }
+            data = load_bootable_image(kname, rname, sname, &sz, cmdline);
             if (data == 0) die("cannot load bootable image");
             fb_queue_flash(pname, data, sz);
         } else if(!strcmp(*argv, "flashall")) {
diff --git a/fastboot/fs.c b/fastboot/fs.c
index cd4b880..8a15e6f 100644
--- a/fastboot/fs.c
+++ b/fastboot/fs.c
@@ -1,5 +1,6 @@
 #include "fastboot.h"
 #include "make_ext4fs.h"
+#include "make_f2fs.h"
 #include "fs.h"
 
 #include <errno.h>
@@ -28,15 +29,23 @@
     return 0;
 }
 
+#ifdef USE_F2FS
+static int generate_f2fs_image(int fd, long long partSize)
+{
+    return make_f2fs_sparse_fd(fd, partSize, NULL, NULL);
+}
+#endif
+
 static const struct fs_generator {
 
     char *fs_type;  //must match what fastboot reports for partition type
     int (*generate)(int fd, long long partSize); //returns 0 or error value
 
 } generators[] = {
-
-    { "ext4", generate_ext4_image}
-
+    { "ext4", generate_ext4_image},
+#ifdef USE_F2FS
+    { "f2fs", generate_f2fs_image},
+#endif
 };
 
 const struct fs_generator* fs_get_generator(const char *fs_type)
diff --git a/fastboot/usb_linux.c b/fastboot/usb_linux.c
index a45f9f8..fabbd51 100644
--- a/fastboot/usb_linux.c
+++ b/fastboot/usb_linux.c
@@ -100,12 +100,12 @@
 
 static int check(void *_desc, int len, unsigned type, int size)
 {
-    unsigned char *desc = _desc;
+    struct usb_descriptor_header *hdr = (struct usb_descriptor_header *)_desc;
 
     if(len < size) return -1;
-    if(desc[0] < size) return -1;
-    if(desc[0] > len) return -1;
-    if(desc[1] != type) return -1;
+    if(hdr->bLength < size) return -1;
+    if(hdr->bLength > len) return -1;
+    if(hdr->bDescriptorType != type) return -1;
 
     return 0;
 }
@@ -125,15 +125,15 @@
     unsigned i;
     unsigned e;
     
-    if(check(ptr, len, USB_DT_DEVICE, USB_DT_DEVICE_SIZE))
+    if (check(ptr, len, USB_DT_DEVICE, USB_DT_DEVICE_SIZE))
         return -1;
-    dev = (void*) ptr;
+    dev = (struct usb_device_descriptor *)ptr;
     len -= dev->bLength;
     ptr += dev->bLength;
 
-    if(check(ptr, len, USB_DT_CONFIG, USB_DT_CONFIG_SIZE))
+    if (check(ptr, len, USB_DT_CONFIG, USB_DT_CONFIG_SIZE))
         return -1;
-    cfg = (void*) ptr;
+    cfg = (struct usb_config_descriptor *)ptr;
     len -= cfg->bLength;
     ptr += cfg->bLength;
 
@@ -177,9 +177,19 @@
     }
 
     for(i = 0; i < cfg->bNumInterfaces; i++) {
-        if(check(ptr, len, USB_DT_INTERFACE, USB_DT_INTERFACE_SIZE))
+
+        while (len > 0) {
+	        struct usb_descriptor_header *hdr = (struct usb_descriptor_header *)ptr;
+            if (check(hdr, len, USB_DT_INTERFACE, USB_DT_INTERFACE_SIZE) == 0)
+                break;
+            len -= hdr->bLength;
+            ptr += hdr->bLength;
+        }
+
+        if (len <= 0)
             return -1;
-        ifc = (void*) ptr;
+
+        ifc = (struct usb_interface_descriptor *)ptr;
         len -= ifc->bLength;
         ptr += ifc->bLength;
 
@@ -190,16 +200,25 @@
         info.ifc_protocol = ifc->bInterfaceProtocol;
 
         for(e = 0; e < ifc->bNumEndpoints; e++) {
-            if(check(ptr, len, USB_DT_ENDPOINT, USB_DT_ENDPOINT_SIZE))
-                return -1;
-            ept = (void*) ptr;
+            while (len > 0) {
+	            struct usb_descriptor_header *hdr = (struct usb_descriptor_header *)ptr;
+                if (check(hdr, len, USB_DT_ENDPOINT, USB_DT_ENDPOINT_SIZE) == 0)
+                    break;
+                len -= hdr->bLength;
+                ptr += hdr->bLength;
+            }
+            if (len < 0) {
+                break;
+            }
+
+            ept = (struct usb_endpoint_descriptor *)ptr;
             len -= ept->bLength;
             ptr += ept->bLength;
 
-            if((ept->bmAttributes & 0x03) != 0x02)
+            if((ept->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK)
                 continue;
 
-            if(ept->bEndpointAddress & 0x80) {
+            if(ept->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
                 in = ept->bEndpointAddress;
             } else {
                 out = ept->bEndpointAddress;
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index dcda005..91e6c33 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -31,6 +31,7 @@
 
 #include <linux/loop.h>
 #include <private/android_filesystem_config.h>
+#include <cutils/android_reboot.h>
 #include <cutils/partition_utils.h>
 #include <cutils/properties.h>
 #include <logwrap/logwrap.h>
@@ -46,6 +47,7 @@
 #define KEY_IN_FOOTER  "footer"
 
 #define E2FSCK_BIN      "/system/bin/e2fsck"
+#define F2FS_FSCK_BIN  "/system/bin/fsck.f2fs"
 #define MKSWAP_BIN      "/system/bin/mkswap"
 
 #define FSCK_LOG_FILE   "/dev/fscklogs/log"
@@ -112,6 +114,7 @@
          * fix the filesystem.
          */
         ret = mount(blk_device, target, fs_type, tmpmnt_flags, tmpmnt_opts);
+        INFO("%s(): mount(%s,%s,%s)=%d\n", __func__, blk_device, target, fs_type, ret);
         if (!ret) {
             umount(target);
         }
@@ -135,6 +138,20 @@
                 ERROR("Failed trying to run %s\n", E2FSCK_BIN);
             }
         }
+    } else if (!strcmp(fs_type, "f2fs")) {
+            char *f2fs_fsck_argv[] = {
+                    F2FS_FSCK_BIN,
+                    blk_device
+            };
+        INFO("Running %s on %s\n", F2FS_FSCK_BIN, blk_device);
+
+        ret = android_fork_execvp_ext(ARRAY_SIZE(f2fs_fsck_argv), f2fs_fsck_argv,
+                                      &status, true, LOG_KLOG | LOG_FILE,
+                                      true, FSCK_LOG_FILE);
+        if (ret < 0) {
+            /* No need to check for error in fork, we can't really handle it now */
+            ERROR("Failed trying to run %s\n", F2FS_FSCK_BIN);
+        }
     }
 
     return;
@@ -175,16 +192,27 @@
  * sets the underlying block device to read-only if the mount is read-only.
  * See "man 2 mount" for return values.
  */
-static int __mount(const char *source, const char *target,
-                   const char *filesystemtype, unsigned long mountflags,
-                   const void *data)
+static int __mount(const char *source, const char *target, const struct fstab_rec *rec)
 {
-    int ret = mount(source, target, filesystemtype, mountflags, data);
+    unsigned long mountflags = rec->flags;
+    int ret;
+    int save_errno;
 
+    /* We need this because sometimes we have legacy symlinks
+     * that are lingering around and need cleaning up.
+     */
+    struct stat info;
+    if (!lstat(target, &info))
+        if ((info.st_mode & S_IFMT) == S_IFLNK)
+            unlink(target);
+    mkdir(target, 0755);
+    ret = mount(source, target, rec->fs_type, mountflags, rec->fs_options);
+    save_errno = errno;
+    INFO("%s(source=%s,target=%s,type=%s)=%d\n", __func__, source, target, rec->fs_type, ret);
     if ((ret == 0) && (mountflags & MS_RDONLY) != 0) {
         fs_set_blk_ro(source);
     }
-
+    errno = save_errno;
     return ret;
 }
 
@@ -208,16 +236,101 @@
     return ret;
 }
 
+static int device_is_debuggable() {
+    int ret = -1;
+    char value[PROP_VALUE_MAX];
+    ret = __system_property_get("ro.debuggable", value);
+    if (ret < 0)
+        return ret;
+    return strcmp(value, "1") ? 0 : 1;
+}
+
+/*
+ * Tries to mount any of the consecutive fstab entries that match
+ * the mountpoint of the one given by fstab->recs[start_idx].
+ *
+ * end_idx: On return, will be the last rec that was looked at.
+ * attempted_idx: On return, will indicate which fstab rec
+ *     succeeded. In case of failure, it will be the start_idx.
+ * Returns
+ *   -1 on failure with errno set to match the 1st mount failure.
+ *   0 on success.
+ */
+static int mount_with_alternatives(struct fstab *fstab, int start_idx, int *end_idx, int *attempted_idx)
+{
+    int i;
+    int mount_errno = 0;
+    int mounted = 0;
+
+    if (!end_idx || !attempted_idx || start_idx >= fstab->num_entries) {
+      errno = EINVAL;
+      if (end_idx) *end_idx = start_idx;
+      if (attempted_idx) *end_idx = start_idx;
+      return -1;
+    }
+
+    /* Hunt down an fstab entry for the same mount point that might succeed */
+    for (i = start_idx;
+         /* We required that fstab entries for the same mountpoint be consecutive */
+         i < fstab->num_entries && !strcmp(fstab->recs[start_idx].mount_point, fstab->recs[i].mount_point);
+         i++) {
+            /*
+             * Don't try to mount/encrypt the same mount point again.
+             * Deal with alternate entries for the same point which are required to be all following
+             * each other.
+             */
+            if (mounted) {
+                ERROR("%s(): skipping fstab dup mountpoint=%s rec[%d].fs_type=%s already mounted as %s.\n", __func__,
+                     fstab->recs[i].mount_point, i, fstab->recs[i].fs_type, fstab->recs[*attempted_idx].fs_type);
+                continue;
+            }
+
+            if (fstab->recs[i].fs_mgr_flags & MF_CHECK) {
+                check_fs(fstab->recs[i].blk_device, fstab->recs[i].fs_type,
+                         fstab->recs[i].mount_point);
+            }
+            if (!__mount(fstab->recs[i].blk_device, fstab->recs[i].mount_point, &fstab->recs[i])) {
+                *attempted_idx = i;
+                mounted = 1;
+                if (i != start_idx) {
+                    ERROR("%s(): Mounted %s on %s with fs_type=%s instead of %s\n", __func__,
+                         fstab->recs[i].blk_device, fstab->recs[i].mount_point, fstab->recs[i].fs_type,
+                         fstab->recs[start_idx].fs_type);
+                }
+            } else {
+                /* back up errno for crypto decisions */
+                mount_errno = errno;
+            }
+    }
+
+    /* Adjust i for the case where it was still withing the recs[] */
+    if (i < fstab->num_entries) --i;
+
+    *end_idx = i;
+    if (!mounted) {
+        *attempted_idx = start_idx;
+        errno = mount_errno;
+        return -1;
+    }
+    return 0;
+}
+
+/* When multiple fstab records share the same mount_point, it will
+ * try to mount each one in turn, and ignore any duplicates after a
+ * first successful mount.
+ * Returns -1 on error, and  FS_MGR_MNTALL_* otherwise.
+ */
 int fs_mgr_mount_all(struct fstab *fstab)
 {
     int i = 0;
-    int encrypted = 0;
-    int ret = -1;
-    int mret;
-    int mount_errno;
+    int encryptable = FS_MGR_MNTALL_DEV_NOT_ENCRYPTED;
+    int error_count = 0;
+    int mret = -1;
+    int mount_errno = 0;
+    int attempted_idx = -1;
 
     if (!fstab) {
-        return ret;
+        return -1;
     }
 
     for (i = 0; i < fstab->num_entries; i++) {
@@ -237,70 +350,92 @@
             wait_for_file(fstab->recs[i].blk_device, WAIT_TIMEOUT);
         }
 
-        if (fstab->recs[i].fs_mgr_flags & MF_CHECK) {
-            check_fs(fstab->recs[i].blk_device, fstab->recs[i].fs_type,
-                     fstab->recs[i].mount_point);
-        }
-
-        if (fstab->recs[i].fs_mgr_flags & MF_VERIFY) {
+        if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) &&
+            !device_is_debuggable()) {
             if (fs_mgr_setup_verity(&fstab->recs[i]) < 0) {
-                ERROR("Could not set up verified partition, skipping!");
+                ERROR("Could not set up verified partition, skipping!\n");
                 continue;
             }
         }
+        int last_idx_inspected;
+        mret = mount_with_alternatives(fstab, i, &last_idx_inspected, &attempted_idx);
+        i = last_idx_inspected;
+        mount_errno = errno;
 
-        mret = __mount(fstab->recs[i].blk_device, fstab->recs[i].mount_point,
-                     fstab->recs[i].fs_type, fstab->recs[i].flags,
-                     fstab->recs[i].fs_options);
-
+        /* Deal with encryptability. */
         if (!mret) {
+            /* If this is encryptable, need to trigger encryption */
+            if ((fstab->recs[attempted_idx].fs_mgr_flags & MF_FORCECRYPT)) {
+                if (umount(fstab->recs[attempted_idx].mount_point) == 0) {
+                    if (encryptable == FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) {
+                        ERROR("Will try to encrypt %s %s\n", fstab->recs[attempted_idx].mount_point,
+                              fstab->recs[attempted_idx].fs_type);
+                        encryptable = FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION;
+                    } else {
+                        ERROR("Only one encryptable/encrypted partition supported\n");
+                        encryptable = FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED;
+                    }
+                } else {
+                    INFO("Could not umount %s - allow continue unencrypted\n",
+                         fstab->recs[attempted_idx].mount_point);
+                    continue;
+                }
+            }
             /* Success!  Go get the next one */
             continue;
         }
 
-        /* back up errno as partition_wipe clobbers the value */
-        mount_errno = errno;
-
-        /* mount(2) returned an error, check if it's encrypted and deal with it */
-        if ((fstab->recs[i].fs_mgr_flags & MF_CRYPT) &&
-            !partition_wiped(fstab->recs[i].blk_device)) {
-            /* Need to mount a tmpfs at this mountpoint for now, and set
-             * properties that vold will query later for decrypting
-             */
-            if (mount("tmpfs", fstab->recs[i].mount_point, "tmpfs",
-                  MS_NOATIME | MS_NOSUID | MS_NODEV, CRYPTO_TMPFS_OPTIONS) < 0) {
-                ERROR("Cannot mount tmpfs filesystem for encrypted fs at %s error: %s\n",
-                        fstab->recs[i].mount_point, strerror(errno));
-                goto out;
+        /* mount(2) returned an error, check if it's encryptable and deal with it */
+        if (mret && mount_errno != EBUSY && mount_errno != EACCES &&
+            fs_mgr_is_encryptable(&fstab->recs[attempted_idx])) {
+            if(partition_wiped(fstab->recs[attempted_idx].blk_device)) {
+                ERROR("%s(): %s is wiped and %s %s is encryptable. Suggest recovery...\n", __func__,
+                      fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point,
+                      fstab->recs[attempted_idx].fs_type);
+                encryptable = FS_MGR_MNTALL_DEV_NEEDS_RECOVERY;
+                continue;
+            } else {
+                /* Need to mount a tmpfs at this mountpoint for now, and set
+                 * properties that vold will query later for decrypting
+                 */
+                ERROR("%s(): possibly an encryptable blkdev %s for mount %s type %s )\n", __func__,
+                      fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point,
+                      fstab->recs[attempted_idx].fs_type);
+                if (fs_mgr_do_tmpfs_mount(fstab->recs[attempted_idx].mount_point) < 0) {
+                    ++error_count;
+                    continue;
+                }
             }
-            encrypted = 1;
+            encryptable = FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED;
         } else {
             ERROR("Failed to mount an un-encryptable or wiped partition on"
-                    "%s at %s options: %s error: %s\n",
-                    fstab->recs[i].blk_device, fstab->recs[i].mount_point,
-                    fstab->recs[i].fs_options, strerror(mount_errno));
-            goto out;
+                   "%s at %s options: %s error: %s\n",
+                   fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point,
+                   fstab->recs[attempted_idx].fs_options, strerror(mount_errno));
+            ++error_count;
+            continue;
         }
     }
 
-    if (encrypted) {
-        ret = 1;
+    if (error_count) {
+        return -1;
     } else {
-        ret = 0;
+        return encryptable;
     }
-
-out:
-    return ret;
 }
 
 /* If tmp_mount_point is non-null, mount the filesystem there.  This is for the
  * tmp mount we do to check the user password
+ * If multiple fstab entries are to be mounted on "n_name", it will try to mount each one
+ * in turn, and stop on 1st success, or no more match.
  */
 int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
                     char *tmp_mount_point)
 {
     int i = 0;
-    int ret = -1;
+    int ret = FS_MGR_DOMNT_FAILED;
+    int mount_errors = 0;
+    int first_mount_errno = 0;
     char *m;
 
     if (!fstab) {
@@ -332,9 +467,10 @@
                      fstab->recs[i].mount_point);
         }
 
-        if (fstab->recs[i].fs_mgr_flags & MF_VERIFY) {
+        if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) &&
+            !device_is_debuggable()) {
             if (fs_mgr_setup_verity(&fstab->recs[i]) < 0) {
-                ERROR("Could not set up verified partition, skipping!");
+                ERROR("Could not set up verified partition, skipping!\n");
                 continue;
             }
         }
@@ -345,19 +481,27 @@
         } else {
             m = fstab->recs[i].mount_point;
         }
-        if (__mount(n_blk_device, m, fstab->recs[i].fs_type,
-                    fstab->recs[i].flags, fstab->recs[i].fs_options)) {
-            ERROR("Cannot mount filesystem on %s at %s options: %s error: %s\n",
-                n_blk_device, m, fstab->recs[i].fs_options, strerror(errno));
-            goto out;
+        if (__mount(n_blk_device, m, &fstab->recs[i])) {
+            if (!first_mount_errno) first_mount_errno = errno;
+            mount_errors++;
+            continue;
         } else {
             ret = 0;
             goto out;
         }
     }
-
-    /* We didn't find a match, say so and return an error */
-    ERROR("Cannot find mount point %s in fstab\n", fstab->recs[i].mount_point);
+    if (mount_errors) {
+        ERROR("Cannot mount filesystem on %s at %s. error: %s\n",
+            n_blk_device, m, strerror(first_mount_errno));
+        if (first_mount_errno == EBUSY) {
+            ret = FS_MGR_DOMNT_BUSY;
+        } else {
+            ret = FS_MGR_DOMNT_FAILED;
+        }
+    } else {
+        /* We didn't find a match, say so and return an error */
+        ERROR("Cannot find mount point %s in fstab\n", fstab->recs[i].mount_point);
+    }
 
 out:
     return ret;
@@ -437,7 +581,7 @@
 
             zram_fp = fopen(ZRAM_CONF_DEV, "r+");
             if (zram_fp == NULL) {
-                ERROR("Unable to open zram conf device " ZRAM_CONF_DEV);
+                ERROR("Unable to open zram conf device %s\n", ZRAM_CONF_DEV);
                 ret = -1;
                 continue;
             }
@@ -504,7 +648,7 @@
         if (fstab->recs[i].fs_mgr_flags & MF_VOLDMANAGED) {
             continue;
         }
-        if (!(fstab->recs[i].fs_mgr_flags & MF_CRYPT)) {
+        if (!(fstab->recs[i].fs_mgr_flags & (MF_CRYPT | MF_FORCECRYPT))) {
             continue;
         }
 
diff --git a/fs_mgr/fs_mgr_fstab.c b/fs_mgr/fs_mgr_fstab.c
index f86fc6a..3f84179 100644
--- a/fs_mgr/fs_mgr_fstab.c
+++ b/fs_mgr/fs_mgr_fstab.c
@@ -59,6 +59,7 @@
     { "wait",        MF_WAIT },
     { "check",       MF_CHECK },
     { "encryptable=",MF_CRYPT },
+    { "forceencrypt=",MF_FORCECRYPT },
     { "nonremovable",MF_NONREMOVABLE },
     { "voldmanaged=",MF_VOLDMANAGED},
     { "length=",     MF_LENGTH },
@@ -106,6 +107,11 @@
                      * location of the keys.  Get it and return it.
                      */
                     flag_vals->key_loc = strdup(strchr(p, '=') + 1);
+                } else if ((fl[i].flag == MF_FORCECRYPT) && flag_vals) {
+                    /* The forceencrypt flag is followed by an = and the
+                     * location of the keys.  Get it and return it.
+                     */
+                    flag_vals->key_loc = strdup(strchr(p, '=') + 1);
                 } else if ((fl[i].flag == MF_LENGTH) && flag_vals) {
                     /* The length flag is followed by an = and the
                      * size of the partition.  Get it and return it.
@@ -361,25 +367,47 @@
      return 0;
 }
 
-struct fstab_rec *fs_mgr_get_entry_for_mount_point(struct fstab *fstab, const char *path)
+/*
+ * Returns the 1st matching fstab_rec that follows the start_rec.
+ * start_rec is the result of a previous search or NULL.
+ */
+struct fstab_rec *fs_mgr_get_entry_for_mount_point_after(struct fstab_rec *start_rec, struct fstab *fstab, const char *path)
 {
     int i;
-
     if (!fstab) {
         return NULL;
     }
 
-    for (i = 0; i < fstab->num_entries; i++) {
+    if (start_rec) {
+        for (i = 0; i < fstab->num_entries; i++) {
+            if (&fstab->recs[i] == start_rec) {
+                i++;
+                break;
+            }
+        }
+    } else {
+        i = 0;
+    }
+    for (; i < fstab->num_entries; i++) {
         int len = strlen(fstab->recs[i].mount_point);
         if (strncmp(path, fstab->recs[i].mount_point, len) == 0 &&
             (path[len] == '\0' || path[len] == '/')) {
             return &fstab->recs[i];
         }
     }
-
     return NULL;
 }
 
+/*
+ * Returns the 1st matching mount point.
+ * There might be more. To look for others, use fs_mgr_get_entry_for_mount_point_after()
+ * and give the fstab_rec from the previous search.
+ */
+struct fstab_rec *fs_mgr_get_entry_for_mount_point(struct fstab *fstab, const char *path)
+{
+    return fs_mgr_get_entry_for_mount_point_after(NULL, fstab, path);
+}
+
 int fs_mgr_is_voldmanaged(struct fstab_rec *fstab)
 {
     return fstab->fs_mgr_flags & MF_VOLDMANAGED;
@@ -392,7 +420,7 @@
 
 int fs_mgr_is_encryptable(struct fstab_rec *fstab)
 {
-    return fstab->fs_mgr_flags & MF_CRYPT;
+    return fstab->fs_mgr_flags & (MF_CRYPT | MF_FORCECRYPT);
 }
 
 int fs_mgr_is_noemulatedsd(struct fstab_rec *fstab)
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 59ffd78..34938fa 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -23,7 +23,7 @@
 #define INFO(x...)    KLOG_INFO("fs_mgr", x)
 #define ERROR(x...)   KLOG_ERROR("fs_mgr", x)
 
-#define CRYPTO_TMPFS_OPTIONS "size=128m,mode=0771,uid=1000,gid=1000"
+#define CRYPTO_TMPFS_OPTIONS "size=256m,mode=0771,uid=1000,gid=1000"
 
 #define WAIT_TIMEOUT 20
 
@@ -72,12 +72,9 @@
 #define MF_SWAPPRIO     0x80
 #define MF_ZRAMSIZE     0x100
 #define MF_VERIFY       0x200
-/*
- * There is no emulated sdcard daemon running on /data/media on this device,
- * so treat the physical SD card as the only external storage device,
- * a la the Nexus One.
- */
-#define MF_NOEMULATEDSD 0x400
+#define MF_FORCECRYPT   0x400
+#define MF_NOEMULATEDSD 0x800 /* no emulated sdcard daemon, sd card is the only
+                                 external storage */
 
 #define DM_BUF_SIZE 4096
 
diff --git a/fs_mgr/fs_mgr_verity.c b/fs_mgr/fs_mgr_verity.c
index c9a2a9b..b79a4a8 100644
--- a/fs_mgr/fs_mgr_verity.c
+++ b/fs_mgr/fs_mgr_verity.c
@@ -30,6 +30,7 @@
 #include <time.h>
 
 #include <private/android_filesystem_config.h>
+#include <cutils/properties.h>
 #include <logwrap/logwrap.h>
 
 #include "mincrypt/rsa.h"
@@ -334,6 +335,26 @@
     return -1;
 }
 
+static int set_verified_property(char *name) {
+    int ret;
+    char *key;
+    ret = asprintf(&key, "partition.%s.verified", name);
+    if (ret < 0) {
+        ERROR("Error formatting verified property");
+        return ret;
+    }
+    ret = PROP_NAME_MAX - strlen(key);
+    if (ret < 0) {
+        ERROR("Verified property name is too long");
+        return -1;
+    }
+    ret = property_set(key, "1");
+    if (ret < 0)
+        ERROR("Error setting verified property %s: %d", key, ret);
+    free(key);
+    return ret;
+}
+
 int fs_mgr_setup_verity(struct fstab_rec *fstab) {
 
     int retval = -1;
@@ -350,6 +371,13 @@
     io->flags |= 1;
     io->target_count = 1;
 
+    // check to ensure that the verity device is ext4
+    // TODO: support non-ext4 filesystems
+    if (strcmp(fstab->fs_type, "ext4")) {
+        ERROR("Cannot verify non-ext4 device (%s)", fstab->fs_type);
+        return retval;
+    }
+
     // get the device mapper fd
     int fd;
     if ((fd = open("/dev/device-mapper", O_RDWR)) < 0) {
@@ -402,7 +430,8 @@
         goto out;
     }
 
-    retval = 0;
+    // set the property indicating that the partition is verified
+    retval = set_verified_property(mount_point);
 
 out:
     close(fd);
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 835cf64..0c7eb20 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -24,6 +24,11 @@
 extern "C" {
 #endif
 
+/*
+ * The entries must be kept in the same order as they were seen in the fstab.
+ * Unless explicitly requested, a lookup on mount point should always
+ * return the 1st one.
+ */
 struct fstab {
     int num_entries;
     struct fstab_rec *recs;
@@ -48,7 +53,15 @@
 
 struct fstab *fs_mgr_read_fstab(const char *fstab_path);
 void fs_mgr_free_fstab(struct fstab *fstab);
+
+#define FS_MGR_MNTALL_DEV_NEEDS_RECOVERY 3
+#define FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION 2
+#define FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED 1
+#define FS_MGR_MNTALL_DEV_NOT_ENCRYPTED 0
 int fs_mgr_mount_all(struct fstab *fstab);
+
+#define FS_MGR_DOMNT_FAILED -1
+#define FS_MGR_DOMNT_BUSY -2
 int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
                     char *tmp_mount_point);
 int fs_mgr_do_tmpfs_mount(char *n_name);
diff --git a/healthd/Android.mk b/healthd/Android.mk
index 473d375..1d238b1 100644
--- a/healthd/Android.mk
+++ b/healthd/Android.mk
@@ -7,12 +7,15 @@
 include $(CLEAR_VARS)
 LOCAL_SRC_FILES := healthd_board_default.cpp
 LOCAL_MODULE := libhealthd.default
+LOCAL_CFLAGS := -Werror
 include $(BUILD_STATIC_LIBRARY)
 
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES := \
 	healthd.cpp \
+	healthd_mode_android.cpp \
+	healthd_mode_charger.cpp \
 	BatteryMonitor.cpp \
 	BatteryPropertiesRegistrar.cpp
 
@@ -22,9 +25,57 @@
 LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN)
 LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED)
 
-LOCAL_STATIC_LIBRARIES :=  libbatteryservice libbinder libz libutils libstdc++ libcutils liblog libm libc
+LOCAL_CFLAGS := -D__STDC_LIMIT_MACROS -Werror
+
+ifeq ($(strip $(BOARD_CHARGER_DISABLE_INIT_BLANK)),true)
+LOCAL_CFLAGS += -DCHARGER_DISABLE_INIT_BLANK
+endif
+
+ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true)
+LOCAL_CFLAGS += -DCHARGER_ENABLE_SUSPEND
+endif
+
+LOCAL_C_INCLUDES := bootable/recovery
+
+LOCAL_STATIC_LIBRARIES := libbatteryservice libbinder libminui libpng libz libutils libstdc++ libcutils liblog libm libc
+
+ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true)
+LOCAL_STATIC_LIBRARIES += libsuspend
+endif
+
 LOCAL_HAL_STATIC_LIBRARIES := libhealthd
 
+# Symlink /charger to /sbin/healthd
+LOCAL_POST_INSTALL_CMD := $(hide) mkdir -p $(TARGET_ROOT_OUT) \
+    && ln -sf /sbin/healthd $(TARGET_ROOT_OUT)/charger
+
 include $(BUILD_EXECUTABLE)
 
+
+define _add-charger-image
+include $$(CLEAR_VARS)
+LOCAL_MODULE := system_core_charger_$(notdir $(1))
+LOCAL_MODULE_STEM := $(notdir $(1))
+_img_modules += $$(LOCAL_MODULE)
+LOCAL_SRC_FILES := $1
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $$(TARGET_ROOT_OUT)/res/images/charger
+include $$(BUILD_PREBUILT)
+endef
+
+_img_modules :=
+_images :=
+$(foreach _img, $(call find-subdir-subdir-files, "images", "*.png"), \
+  $(eval $(call _add-charger-image,$(_img))))
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := charger_res_images
+LOCAL_MODULE_TAGS := optional
+LOCAL_REQUIRED_MODULES := $(_img_modules)
+include $(BUILD_PHONY_PACKAGE)
+
+_add-charger-image :=
+_img_modules :=
+
 endif
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index 688c7ff..4a6b702 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -18,7 +18,6 @@
 
 #include "healthd.h"
 #include "BatteryMonitor.h"
-#include "BatteryPropertiesRegistrar.h"
 
 #include <dirent.h>
 #include <errno.h>
@@ -28,16 +27,21 @@
 #include <unistd.h>
 #include <batteryservice/BatteryService.h>
 #include <cutils/klog.h>
+#include <cutils/properties.h>
+#include <sys/types.h>
+#include <utils/Errors.h>
 #include <utils/String8.h>
 #include <utils/Vector.h>
 
 #define POWER_SUPPLY_SUBSYSTEM "power_supply"
 #define POWER_SUPPLY_SYSFS_PATH "/sys/class/" POWER_SUPPLY_SUBSYSTEM
+#define FAKE_BATTERY_CAPACITY 42
+#define FAKE_BATTERY_TEMPERATURE 424
 
 namespace android {
 
 struct sysfsStringEnumMap {
-    char* s;
+    const char* s;
     int val;
 };
 
@@ -170,7 +174,6 @@
 }
 
 bool BatteryMonitor::update(void) {
-    struct BatteryProperties props;
     bool logthis;
 
     props.chargerAcOnline = false;
@@ -178,24 +181,20 @@
     props.chargerWirelessOnline = false;
     props.batteryStatus = BATTERY_STATUS_UNKNOWN;
     props.batteryHealth = BATTERY_HEALTH_UNKNOWN;
-    props.batteryCurrentNow = INT_MIN;
-    props.batteryChargeCounter = INT_MIN;
 
     if (!mHealthdConfig->batteryPresentPath.isEmpty())
         props.batteryPresent = getBooleanField(mHealthdConfig->batteryPresentPath);
     else
-        props.batteryPresent = true;
+        props.batteryPresent = mBatteryDevicePresent;
 
-    props.batteryLevel = getIntField(mHealthdConfig->batteryCapacityPath);
+    props.batteryLevel = mBatteryFixedCapacity ?
+        mBatteryFixedCapacity :
+        getIntField(mHealthdConfig->batteryCapacityPath);
     props.batteryVoltage = getIntField(mHealthdConfig->batteryVoltagePath) / 1000;
 
-    if (!mHealthdConfig->batteryCurrentNowPath.isEmpty())
-        props.batteryCurrentNow = getIntField(mHealthdConfig->batteryCurrentNowPath);
-
-    if (!mHealthdConfig->batteryChargeCounterPath.isEmpty())
-        props.batteryChargeCounter = getIntField(mHealthdConfig->batteryChargeCounterPath);
-
-    props.batteryTemperature = getIntField(mHealthdConfig->batteryTemperaturePath);
+    props.batteryTemperature = mBatteryFixedTemperature ?
+        mBatteryFixedTemperature :
+        getIntField(mHealthdConfig->batteryTemperaturePath);
 
     const int SIZE = 128;
     char buf[SIZE];
@@ -244,7 +243,9 @@
 
     if (logthis) {
         char dmesgline[256];
-        snprintf(dmesgline, sizeof(dmesgline),
+
+        if (props.batteryPresent) {
+            snprintf(dmesgline, sizeof(dmesgline),
                  "battery l=%d v=%d t=%s%d.%d h=%d st=%d",
                  props.batteryLevel, props.batteryVoltage,
                  props.batteryTemperature < 0 ? "-" : "",
@@ -252,11 +253,16 @@
                  abs(props.batteryTemperature % 10), props.batteryHealth,
                  props.batteryStatus);
 
-        if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
-            char b[20];
+            if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
+                int c = getIntField(mHealthdConfig->batteryCurrentNowPath);
+                char b[20];
 
-            snprintf(b, sizeof(b), " c=%d", props.batteryCurrentNow / 1000);
-            strlcat(dmesgline, b, sizeof(dmesgline));
+                snprintf(b, sizeof(b), " c=%d", c / 1000);
+                strlcat(dmesgline, b, sizeof(dmesgline));
+            }
+        } else {
+            snprintf(dmesgline, sizeof(dmesgline),
+                 "battery none");
         }
 
         KLOG_INFO(LOG_TAG, "%s chg=%s%s%s\n", dmesgline,
@@ -265,15 +271,110 @@
                   props.chargerWirelessOnline ? "w" : "");
     }
 
-    if (mBatteryPropertiesRegistrar != NULL)
-        mBatteryPropertiesRegistrar->notifyListeners(props);
-
+    healthd_mode_ops->battery_update(&props);
     return props.chargerAcOnline | props.chargerUsbOnline |
             props.chargerWirelessOnline;
 }
 
-void BatteryMonitor::init(struct healthd_config *hc, bool nosvcmgr) {
+status_t BatteryMonitor::getProperty(int id, struct BatteryProperty *val) {
+    status_t ret = BAD_VALUE;
+
+    val->valueInt64 = LONG_MIN;
+
+    switch(id) {
+    case BATTERY_PROP_CHARGE_COUNTER:
+        if (!mHealthdConfig->batteryChargeCounterPath.isEmpty()) {
+            val->valueInt64 =
+                getIntField(mHealthdConfig->batteryChargeCounterPath);
+            ret = NO_ERROR;
+        } else {
+            ret = NAME_NOT_FOUND;
+        }
+        break;
+
+    case BATTERY_PROP_CURRENT_NOW:
+        if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
+            val->valueInt64 =
+                getIntField(mHealthdConfig->batteryCurrentNowPath);
+            ret = NO_ERROR;
+        } else {
+            ret = NAME_NOT_FOUND;
+        }
+        break;
+
+    case BATTERY_PROP_CURRENT_AVG:
+        if (!mHealthdConfig->batteryCurrentAvgPath.isEmpty()) {
+            val->valueInt64 =
+                getIntField(mHealthdConfig->batteryCurrentAvgPath);
+            ret = NO_ERROR;
+        } else {
+            ret = NAME_NOT_FOUND;
+        }
+        break;
+
+    case BATTERY_PROP_CAPACITY:
+        if (!mHealthdConfig->batteryCapacityPath.isEmpty()) {
+            val->valueInt64 =
+                getIntField(mHealthdConfig->batteryCapacityPath);
+            ret = NO_ERROR;
+        } else {
+            ret = NAME_NOT_FOUND;
+        }
+        break;
+
+    case BATTERY_PROP_ENERGY_COUNTER:
+        if (mHealthdConfig->energyCounter) {
+            ret = mHealthdConfig->energyCounter(&val->valueInt64);
+        } else {
+            ret = NAME_NOT_FOUND;
+        }
+        break;
+
+    default:
+        break;
+    }
+
+    return ret;
+}
+
+void BatteryMonitor::dumpState(int fd) {
+    int v;
+    char vs[128];
+
+    snprintf(vs, sizeof(vs), "ac: %d usb: %d wireless: %d\n",
+             props.chargerAcOnline, props.chargerUsbOnline,
+             props.chargerWirelessOnline);
+    write(fd, vs, strlen(vs));
+    snprintf(vs, sizeof(vs), "status: %d health: %d present: %d\n",
+             props.batteryStatus, props.batteryHealth, props.batteryPresent);
+    write(fd, vs, strlen(vs));
+    snprintf(vs, sizeof(vs), "level: %d voltage: %d temp: %d\n",
+             props.batteryLevel, props.batteryVoltage,
+             props.batteryTemperature);
+    write(fd, vs, strlen(vs));
+
+    if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
+        v = getIntField(mHealthdConfig->batteryCurrentNowPath);
+        snprintf(vs, sizeof(vs), "current now: %d\n", v);
+        write(fd, vs, strlen(vs));
+    }
+
+    if (!mHealthdConfig->batteryCurrentAvgPath.isEmpty()) {
+        v = getIntField(mHealthdConfig->batteryCurrentAvgPath);
+        snprintf(vs, sizeof(vs), "current avg: %d\n", v);
+        write(fd, vs, strlen(vs));
+    }
+
+    if (!mHealthdConfig->batteryChargeCounterPath.isEmpty()) {
+        v = getIntField(mHealthdConfig->batteryChargeCounterPath);
+        snprintf(vs, sizeof(vs), "charge counter: %d\n", v);
+        write(fd, vs, strlen(vs));
+    }
+}
+
+void BatteryMonitor::init(struct healthd_config *hc) {
     String8 path;
+    char pval[PROPERTY_VALUE_MAX];
 
     mHealthdConfig = hc;
     DIR* dir = opendir(POWER_SUPPLY_SYSFS_PATH);
@@ -303,6 +404,8 @@
                 break;
 
             case ANDROID_POWER_SUPPLY_TYPE_BATTERY:
+                mBatteryDevicePresent = true;
+
                 if (mHealthdConfig->batteryStatusPath.isEmpty()) {
                     path.clear();
                     path.appendFormat("%s/%s/status", POWER_SUPPLY_SYSFS_PATH,
@@ -358,6 +461,14 @@
                         mHealthdConfig->batteryCurrentNowPath = path;
                 }
 
+                if (mHealthdConfig->batteryCurrentAvgPath.isEmpty()) {
+                    path.clear();
+                    path.appendFormat("%s/%s/current_avg",
+                                      POWER_SUPPLY_SYSFS_PATH, name);
+                    if (access(path, R_OK) == 0)
+                        mHealthdConfig->batteryCurrentAvgPath = path;
+                }
+
                 if (mHealthdConfig->batteryChargeCounterPath.isEmpty()) {
                     path.clear();
                     path.appendFormat("%s/%s/charge_counter",
@@ -400,24 +511,31 @@
 
     if (!mChargerNames.size())
         KLOG_ERROR(LOG_TAG, "No charger supplies found\n");
-    if (mHealthdConfig->batteryStatusPath.isEmpty())
-        KLOG_WARNING(LOG_TAG, "BatteryStatusPath not found\n");
-    if (mHealthdConfig->batteryHealthPath.isEmpty())
-        KLOG_WARNING(LOG_TAG, "BatteryHealthPath not found\n");
-    if (mHealthdConfig->batteryPresentPath.isEmpty())
-        KLOG_WARNING(LOG_TAG, "BatteryPresentPath not found\n");
-    if (mHealthdConfig->batteryCapacityPath.isEmpty())
-        KLOG_WARNING(LOG_TAG, "BatteryCapacityPath not found\n");
-    if (mHealthdConfig->batteryVoltagePath.isEmpty())
-        KLOG_WARNING(LOG_TAG, "BatteryVoltagePath not found\n");
-    if (mHealthdConfig->batteryTemperaturePath.isEmpty())
-        KLOG_WARNING(LOG_TAG, "BatteryTemperaturePath not found\n");
-    if (mHealthdConfig->batteryTechnologyPath.isEmpty())
-        KLOG_WARNING(LOG_TAG, "BatteryTechnologyPath not found\n");
+    if (!mBatteryDevicePresent) {
+        KLOG_INFO(LOG_TAG, "No battery devices found\n");
+        hc->periodic_chores_interval_fast = -1;
+        hc->periodic_chores_interval_slow = -1;
+    } else {
+        if (mHealthdConfig->batteryStatusPath.isEmpty())
+            KLOG_WARNING(LOG_TAG, "BatteryStatusPath not found\n");
+        if (mHealthdConfig->batteryHealthPath.isEmpty())
+            KLOG_WARNING(LOG_TAG, "BatteryHealthPath not found\n");
+        if (mHealthdConfig->batteryPresentPath.isEmpty())
+            KLOG_WARNING(LOG_TAG, "BatteryPresentPath not found\n");
+        if (mHealthdConfig->batteryCapacityPath.isEmpty())
+            KLOG_WARNING(LOG_TAG, "BatteryCapacityPath not found\n");
+        if (mHealthdConfig->batteryVoltagePath.isEmpty())
+            KLOG_WARNING(LOG_TAG, "BatteryVoltagePath not found\n");
+        if (mHealthdConfig->batteryTemperaturePath.isEmpty())
+            KLOG_WARNING(LOG_TAG, "BatteryTemperaturePath not found\n");
+        if (mHealthdConfig->batteryTechnologyPath.isEmpty())
+            KLOG_WARNING(LOG_TAG, "BatteryTechnologyPath not found\n");
+    }
 
-    if (nosvcmgr == false) {
-            mBatteryPropertiesRegistrar = new BatteryPropertiesRegistrar(this);
-            mBatteryPropertiesRegistrar->publish();
+    if (property_get("ro.boot.fake_battery", pval, NULL) > 0
+                                               && strtol(pval, NULL, 10) != 0) {
+        mBatteryFixedCapacity = FAKE_BATTERY_CAPACITY;
+        mBatteryFixedTemperature = FAKE_BATTERY_TEMPERATURE;
     }
 }
 
diff --git a/healthd/BatteryMonitor.h b/healthd/BatteryMonitor.h
index ba291af..3425f27 100644
--- a/healthd/BatteryMonitor.h
+++ b/healthd/BatteryMonitor.h
@@ -17,17 +17,15 @@
 #ifndef HEALTHD_BATTERYMONITOR_H
 #define HEALTHD_BATTERYMONITOR_H
 
+#include <batteryservice/BatteryService.h>
 #include <binder/IInterface.h>
 #include <utils/String8.h>
 #include <utils/Vector.h>
 
 #include "healthd.h"
-#include "BatteryPropertiesRegistrar.h"
 
 namespace android {
 
-class BatteryPropertiesRegistrar;
-
 class BatteryMonitor {
   public:
 
@@ -39,14 +37,18 @@
         ANDROID_POWER_SUPPLY_TYPE_BATTERY
     };
 
-    void init(struct healthd_config *hc, bool nosvcmgr);
+    void init(struct healthd_config *hc);
     bool update(void);
+    status_t getProperty(int id, struct BatteryProperty *val);
+    void dumpState(int fd);
 
   private:
     struct healthd_config *mHealthdConfig;
     Vector<String8> mChargerNames;
-
-    sp<BatteryPropertiesRegistrar> mBatteryPropertiesRegistrar;
+    bool mBatteryDevicePresent;
+    int mBatteryFixedCapacity;
+    int mBatteryFixedTemperature;
+    struct BatteryProperties props;
 
     int getBatteryStatus(const char* status);
     int getBatteryHealth(const char* status);
diff --git a/healthd/BatteryPropertiesRegistrar.cpp b/healthd/BatteryPropertiesRegistrar.cpp
index 6a33ad8..74bcbfd 100644
--- a/healthd/BatteryPropertiesRegistrar.cpp
+++ b/healthd/BatteryPropertiesRegistrar.cpp
@@ -18,19 +18,20 @@
 #include <batteryservice/BatteryService.h>
 #include <batteryservice/IBatteryPropertiesListener.h>
 #include <batteryservice/IBatteryPropertiesRegistrar.h>
+#include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
+#include <binder/PermissionCache.h>
+#include <private/android_filesystem_config.h>
 #include <utils/Errors.h>
 #include <utils/Mutex.h>
 #include <utils/String16.h>
 
+#include "healthd.h"
+
 namespace android {
 
-BatteryPropertiesRegistrar::BatteryPropertiesRegistrar(BatteryMonitor* monitor) {
-    mBatteryMonitor = monitor;
-}
-
 void BatteryPropertiesRegistrar::publish() {
-    defaultServiceManager()->addService(String16("batterypropreg"), this);
+    defaultServiceManager()->addService(String16("batteryproperties"), this);
 }
 
 void BatteryPropertiesRegistrar::notifyListeners(struct BatteryProperties props) {
@@ -42,6 +43,8 @@
 
 void BatteryPropertiesRegistrar::registerListener(const sp<IBatteryPropertiesListener>& listener) {
     {
+        if (listener == NULL)
+            return;
         Mutex::Autolock _l(mRegistrationLock);
         // check whether this is a duplicate
         for (size_t i = 0; i < mListeners.size(); i++) {
@@ -53,10 +56,12 @@
         mListeners.add(listener);
         listener->asBinder()->linkToDeath(this);
     }
-    mBatteryMonitor->update();
+    healthd_battery_update();
 }
 
 void BatteryPropertiesRegistrar::unregisterListener(const sp<IBatteryPropertiesListener>& listener) {
+    if (listener == NULL)
+        return;
     Mutex::Autolock _l(mRegistrationLock);
     for (size_t i = 0; i < mListeners.size(); i++) {
         if (mListeners[i]->asBinder() == listener->asBinder()) {
@@ -67,6 +72,23 @@
     }
 }
 
+status_t BatteryPropertiesRegistrar::getProperty(int id, struct BatteryProperty *val) {
+    return healthd_get_property(id, val);
+}
+
+status_t BatteryPropertiesRegistrar::dump(int fd, const Vector<String16>& /*args*/) {
+    IPCThreadState* self = IPCThreadState::self();
+    const int pid = self->getCallingPid();
+    const int uid = self->getCallingUid();
+    if ((uid != AID_SHELL) &&
+        !PermissionCache::checkPermission(
+                String16("android.permission.DUMP"), pid, uid))
+        return PERMISSION_DENIED;
+
+    healthd_dump_battery_state(fd);
+    return OK;
+}
+
 void BatteryPropertiesRegistrar::binderDied(const wp<IBinder>& who) {
     Mutex::Autolock _l(mRegistrationLock);
 
diff --git a/healthd/BatteryPropertiesRegistrar.h b/healthd/BatteryPropertiesRegistrar.h
index 793ddad..8853874 100644
--- a/healthd/BatteryPropertiesRegistrar.h
+++ b/healthd/BatteryPropertiesRegistrar.h
@@ -17,10 +17,9 @@
 #ifndef HEALTHD_BATTERYPROPERTIES_REGISTRAR_H
 #define HEALTHD_BATTERYPROPERTIES_REGISTRAR_H
 
-#include "BatteryMonitor.h"
-
 #include <binder/IBinder.h>
 #include <utils/Mutex.h>
+#include <utils/String16.h>
 #include <utils/Vector.h>
 #include <batteryservice/BatteryService.h>
 #include <batteryservice/IBatteryPropertiesListener.h>
@@ -28,22 +27,20 @@
 
 namespace android {
 
-class BatteryMonitor;
-
 class BatteryPropertiesRegistrar : public BnBatteryPropertiesRegistrar,
                                    public IBinder::DeathRecipient {
 public:
-    BatteryPropertiesRegistrar(BatteryMonitor* monitor);
     void publish();
     void notifyListeners(struct BatteryProperties props);
 
 private:
-    BatteryMonitor* mBatteryMonitor;
     Mutex mRegistrationLock;
     Vector<sp<IBatteryPropertiesListener> > mListeners;
 
     void registerListener(const sp<IBatteryPropertiesListener>& listener);
     void unregisterListener(const sp<IBatteryPropertiesListener>& listener);
+    status_t getProperty(int id, struct BatteryProperty *val);
+    status_t dump(int fd, const Vector<String16>& args);
     void binderDied(const wp<IBinder>& who);
 };
 
diff --git a/healthd/healthd.cpp b/healthd/healthd.cpp
index d30e771..30a4b42 100644
--- a/healthd/healthd.cpp
+++ b/healthd/healthd.cpp
@@ -21,16 +21,17 @@
 #include "BatteryMonitor.h"
 
 #include <errno.h>
+#include <libgen.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 #include <batteryservice/BatteryService.h>
-#include <binder/IPCThreadState.h>
-#include <binder/ProcessState.h>
 #include <cutils/klog.h>
 #include <cutils/uevent.h>
 #include <sys/epoll.h>
 #include <sys/timerfd.h>
+#include <utils/Errors.h>
 
 using namespace android;
 
@@ -49,13 +50,18 @@
     .batteryTemperaturePath = String8(String8::kEmptyString),
     .batteryTechnologyPath = String8(String8::kEmptyString),
     .batteryCurrentNowPath = String8(String8::kEmptyString),
+    .batteryCurrentAvgPath = String8(String8::kEmptyString),
     .batteryChargeCounterPath = String8(String8::kEmptyString),
+    .energyCounter = NULL,
 };
 
+static int eventct;
+static int epollfd;
+
 #define POWER_SUPPLY_SUBSYSTEM "power_supply"
 
-// epoll events: uevent, wakealarm, binder
-#define MAX_EPOLL_EVENTS 3
+// epoll_create() parameter is actually unused
+#define MAX_EPOLL_EVENTS 40
 static int uevent_fd;
 static int wakealarm_fd;
 static int binder_fd;
@@ -67,7 +73,80 @@
 
 static BatteryMonitor* gBatteryMonitor;
 
-static bool nosvcmgr;
+struct healthd_mode_ops *healthd_mode_ops;
+
+// Android mode
+
+extern void healthd_mode_android_init(struct healthd_config *config);
+extern int healthd_mode_android_preparetowait(void);
+extern void healthd_mode_android_battery_update(
+    struct android::BatteryProperties *props);
+
+// Charger mode
+
+extern void healthd_mode_charger_init(struct healthd_config *config);
+extern int healthd_mode_charger_preparetowait(void);
+extern void healthd_mode_charger_heartbeat(void);
+extern void healthd_mode_charger_battery_update(
+    struct android::BatteryProperties *props);
+
+// NOPs for modes that need no special action
+
+static void healthd_mode_nop_init(struct healthd_config *config);
+static int healthd_mode_nop_preparetowait(void);
+static void healthd_mode_nop_heartbeat(void);
+static void healthd_mode_nop_battery_update(
+    struct android::BatteryProperties *props);
+
+static struct healthd_mode_ops android_ops = {
+    .init = healthd_mode_android_init,
+    .preparetowait = healthd_mode_android_preparetowait,
+    .heartbeat = healthd_mode_nop_heartbeat,
+    .battery_update = healthd_mode_android_battery_update,
+};
+
+static struct healthd_mode_ops charger_ops = {
+    .init = healthd_mode_charger_init,
+    .preparetowait = healthd_mode_charger_preparetowait,
+    .heartbeat = healthd_mode_charger_heartbeat,
+    .battery_update = healthd_mode_charger_battery_update,
+};
+
+static struct healthd_mode_ops recovery_ops = {
+    .init = healthd_mode_nop_init,
+    .preparetowait = healthd_mode_nop_preparetowait,
+    .heartbeat = healthd_mode_nop_heartbeat,
+    .battery_update = healthd_mode_nop_battery_update,
+};
+
+static void healthd_mode_nop_init(struct healthd_config* /*config*/) {
+}
+
+static int healthd_mode_nop_preparetowait(void) {
+    return -1;
+}
+
+static void healthd_mode_nop_heartbeat(void) {
+}
+
+static void healthd_mode_nop_battery_update(
+    struct android::BatteryProperties* /*props*/) {
+}
+
+int healthd_register_event(int fd, void (*handler)(uint32_t)) {
+    struct epoll_event ev;
+
+    ev.events = EPOLLIN | EPOLLWAKEUP;
+    ev.data.ptr = (void *)handler;
+    if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
+        KLOG_ERROR(LOG_TAG,
+                   "epoll_ctl failed; errno=%d\n", errno);
+        return -1;
+    }
+
+    eventct++;
+    return 0;
+}
 
 static void wakealarm_set_interval(int interval) {
     struct itimerspec itval;
@@ -89,7 +168,11 @@
         KLOG_ERROR(LOG_TAG, "wakealarm_set_interval: timerfd_settime failed\n");
 }
 
-static void battery_update(void) {
+status_t healthd_get_property(int id, struct BatteryProperty *val) {
+    return gBatteryMonitor->getProperty(id, val);
+}
+
+void healthd_battery_update(void) {
     // Fast wake interval when on charger (watch for overheat);
     // slow wake interval when on battery (watch for drained battery).
 
@@ -113,21 +196,17 @@
                 -1 : healthd_config.periodic_chores_interval_fast * 1000;
 }
 
-static void periodic_chores() {
-    battery_update();
+void healthd_dump_battery_state(int fd) {
+    gBatteryMonitor->dumpState(fd);
+    fsync(fd);
 }
 
-static void uevent_init(void) {
-    uevent_fd = uevent_open_socket(64*1024, true);
-
-    if (uevent_fd >= 0)
-        fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
-    else
-        KLOG_ERROR(LOG_TAG, "uevent_init: uevent_open_socket failed\n");
+static void periodic_chores() {
+    healthd_battery_update();
 }
 
 #define UEVENT_MSG_LEN 2048
-static void uevent_event(void) {
+static void uevent_event(uint32_t /*epevents*/) {
     char msg[UEVENT_MSG_LEN+2];
     char *cp;
     int n;
@@ -144,7 +223,7 @@
 
     while (*cp) {
         if (!strcmp(cp, "SUBSYSTEM=" POWER_SUPPLY_SUBSYSTEM)) {
-            battery_update();
+            healthd_battery_update();
             break;
         }
 
@@ -154,6 +233,31 @@
     }
 }
 
+static void uevent_init(void) {
+    uevent_fd = uevent_open_socket(64*1024, true);
+
+    if (uevent_fd < 0) {
+        KLOG_ERROR(LOG_TAG, "uevent_init: uevent_open_socket failed\n");
+        return;
+    }
+
+    fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
+    if (healthd_register_event(uevent_fd, uevent_event))
+        KLOG_ERROR(LOG_TAG,
+                   "register for uevent events failed\n");
+}
+
+static void wakealarm_event(uint32_t /*epevents*/) {
+    unsigned long long wakeups;
+
+    if (read(wakealarm_fd, &wakeups, sizeof(wakeups)) == -1) {
+        KLOG_ERROR(LOG_TAG, "wakealarm_event: read wakealarm fd failed\n");
+        return;
+    }
+
+    periodic_chores();
+}
+
 static void wakealarm_init(void) {
     wakealarm_fd = timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK);
     if (wakealarm_fd == -1) {
@@ -161,82 +265,24 @@
         return;
     }
 
+    if (healthd_register_event(wakealarm_fd, wakealarm_event))
+        KLOG_ERROR(LOG_TAG,
+                   "Registration of wakealarm event failed\n");
+
     wakealarm_set_interval(healthd_config.periodic_chores_interval_fast);
 }
 
-static void wakealarm_event(void) {
-    unsigned long long wakeups;
-
-    if (read(wakealarm_fd, &wakeups, sizeof(wakeups)) == -1) {
-        KLOG_ERROR(LOG_TAG, "wakealarm_event: read wakealarm_fd failed\n");
-        return;
-    }
-
-    periodic_chores();
-}
-
-static void binder_init(void) {
-    ProcessState::self()->setThreadPoolMaxThreadCount(0);
-    IPCThreadState::self()->disableBackgroundScheduling(true);
-    IPCThreadState::self()->setupPolling(&binder_fd);
-}
-
-static void binder_event(void) {
-    IPCThreadState::self()->handlePolledCommands();
-}
-
 static void healthd_mainloop(void) {
-    struct epoll_event ev;
-    int epollfd;
-    int maxevents = 0;
-
-    epollfd = epoll_create(MAX_EPOLL_EVENTS);
-    if (epollfd == -1) {
-        KLOG_ERROR(LOG_TAG,
-                   "healthd_mainloop: epoll_create failed; errno=%d\n",
-                   errno);
-        return;
-    }
-
-    if (uevent_fd >= 0) {
-        ev.events = EPOLLIN | EPOLLWAKEUP;
-        ev.data.ptr = (void *)uevent_event;
-        if (epoll_ctl(epollfd, EPOLL_CTL_ADD, uevent_fd, &ev) == -1)
-            KLOG_ERROR(LOG_TAG,
-                       "healthd_mainloop: epoll_ctl for uevent_fd failed; errno=%d\n",
-                       errno);
-        else
-            maxevents++;
-    }
-
-    if (wakealarm_fd >= 0) {
-        ev.events = EPOLLIN | EPOLLWAKEUP;
-        ev.data.ptr = (void *)wakealarm_event;
-        if (epoll_ctl(epollfd, EPOLL_CTL_ADD, wakealarm_fd, &ev) == -1)
-            KLOG_ERROR(LOG_TAG,
-                       "healthd_mainloop: epoll_ctl for wakealarm_fd failed; errno=%d\n",
-                       errno);
-        else
-            maxevents++;
-   }
-
-    if (binder_fd >= 0) {
-        ev.events = EPOLLIN | EPOLLWAKEUP;
-        ev.data.ptr= (void *)binder_event;
-        if (epoll_ctl(epollfd, EPOLL_CTL_ADD, binder_fd, &ev) == -1)
-            KLOG_ERROR(LOG_TAG,
-                       "healthd_mainloop: epoll_ctl for binder_fd failed; errno=%d\n",
-                       errno);
-        else
-            maxevents++;
-   }
-
     while (1) {
-        struct epoll_event events[maxevents];
+        struct epoll_event events[eventct];
         int nevents;
+        int timeout = awake_poll_interval;
+        int mode_timeout;
 
-        IPCThreadState::self()->flushCommands();
-        nevents = epoll_wait(epollfd, events, maxevents, awake_poll_interval);
+        mode_timeout = healthd_mode_ops->preparetowait();
+        if (timeout < 0 || (mode_timeout > 0 && mode_timeout < timeout))
+            timeout = mode_timeout;
+        nevents = epoll_wait(epollfd, events, eventct, timeout);
 
         if (nevents == -1) {
             if (errno == EINTR)
@@ -247,39 +293,70 @@
 
         for (int n = 0; n < nevents; ++n) {
             if (events[n].data.ptr)
-                (*(void (*)())events[n].data.ptr)();
+                (*(void (*)(int))events[n].data.ptr)(events[n].events);
         }
 
         if (!nevents)
             periodic_chores();
+
+        healthd_mode_ops->heartbeat();
     }
 
     return;
 }
 
-int main(int argc, char **argv) {
-    int ch;
-
-    klog_set_level(KLOG_LEVEL);
-
-    while ((ch = getopt(argc, argv, "n")) != -1) {
-        switch (ch) {
-        case 'n':
-            nosvcmgr = true;
-            break;
-        case '?':
-        default:
-            KLOG_WARNING(LOG_TAG, "Unrecognized healthd option: %c\n", ch);
-        }
+static int healthd_init() {
+    epollfd = epoll_create(MAX_EPOLL_EVENTS);
+    if (epollfd == -1) {
+        KLOG_ERROR(LOG_TAG,
+                   "epoll_create failed; errno=%d\n",
+                   errno);
+        return -1;
     }
 
+    healthd_mode_ops->init(&healthd_config);
     healthd_board_init(&healthd_config);
     wakealarm_init();
     uevent_init();
-    binder_init();
     gBatteryMonitor = new BatteryMonitor();
-    gBatteryMonitor->init(&healthd_config, nosvcmgr);
+    gBatteryMonitor->init(&healthd_config);
+    return 0;
+}
+
+int main(int argc, char **argv) {
+    int ch;
+    int ret;
+
+    klog_set_level(KLOG_LEVEL);
+    healthd_mode_ops = &android_ops;
+
+    if (!strcmp(basename(argv[0]), "charger")) {
+        healthd_mode_ops = &charger_ops;
+    } else {
+        while ((ch = getopt(argc, argv, "cr")) != -1) {
+            switch (ch) {
+            case 'c':
+                healthd_mode_ops = &charger_ops;
+                break;
+            case 'r':
+                healthd_mode_ops = &recovery_ops;
+                break;
+            case '?':
+            default:
+                KLOG_ERROR(LOG_TAG, "Unrecognized healthd option: %c\n",
+                           optopt);
+                exit(1);
+            }
+        }
+    }
+
+    ret = healthd_init();
+    if (ret) {
+        KLOG_ERROR("Initialization failed, exiting\n");
+        exit(2);
+    }
 
     healthd_mainloop();
-    return 0;
+    KLOG_ERROR("Main loop terminated, exiting\n");
+    return 3;
 }
diff --git a/healthd/healthd.h b/healthd/healthd.h
index 5374fb1..972e728 100644
--- a/healthd/healthd.h
+++ b/healthd/healthd.h
@@ -18,6 +18,8 @@
 #define _HEALTHD_H_
 
 #include <batteryservice/BatteryService.h>
+#include <sys/types.h>
+#include <utils/Errors.h>
 #include <utils/String8.h>
 
 // periodic_chores_interval_fast, periodic_chores_interval_slow: intervals at
@@ -61,9 +63,37 @@
     android::String8 batteryTemperaturePath;
     android::String8 batteryTechnologyPath;
     android::String8 batteryCurrentNowPath;
+    android::String8 batteryCurrentAvgPath;
     android::String8 batteryChargeCounterPath;
+
+    int (*energyCounter)(int64_t *);
 };
 
+// Global helper functions
+
+int healthd_register_event(int fd, void (*handler)(uint32_t));
+void healthd_battery_update();
+android::status_t healthd_get_property(int id,
+    struct android::BatteryProperty *val);
+void healthd_dump_battery_state(int fd);
+
+struct healthd_mode_ops {
+    void (*init)(struct healthd_config *config);
+    int (*preparetowait)(void);
+    void (*heartbeat)(void);
+    void (*battery_update)(struct android::BatteryProperties *props);
+};
+
+extern struct healthd_mode_ops *healthd_mode_ops;
+
+// Charger mode
+
+void healthd_mode_charger_init(struct healthd_config *config);
+int healthd_mode_charger_preparetowait(void);
+void healthd_mode_charger_heartbeat(void);
+void healthd_mode_charger_battery_update(
+    struct android::BatteryProperties *props);
+
 // The following are implemented in libhealthd_board to handle board-specific
 // behavior.
 //
diff --git a/healthd/healthd_mode_android.cpp b/healthd/healthd_mode_android.cpp
new file mode 100644
index 0000000..fd153a2
--- /dev/null
+++ b/healthd/healthd_mode_android.cpp
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "healthd-android"
+
+#include "healthd.h"
+#include "BatteryPropertiesRegistrar.h"
+
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <cutils/klog.h>
+#include <sys/epoll.h>
+
+using namespace android;
+
+static int gBinderFd;
+static sp<BatteryPropertiesRegistrar> gBatteryPropertiesRegistrar;
+
+void healthd_mode_android_battery_update(
+    struct android::BatteryProperties *props) {
+    if (gBatteryPropertiesRegistrar != NULL)
+        gBatteryPropertiesRegistrar->notifyListeners(*props);
+
+    return;
+}
+
+int healthd_mode_android_preparetowait(void) {
+    IPCThreadState::self()->flushCommands();
+    return -1;
+}
+
+static void binder_event(uint32_t /*epevents*/) {
+    IPCThreadState::self()->handlePolledCommands();
+}
+
+void healthd_mode_android_init(struct healthd_config* /*config*/) {
+    ProcessState::self()->setThreadPoolMaxThreadCount(0);
+    IPCThreadState::self()->disableBackgroundScheduling(true);
+    IPCThreadState::self()->setupPolling(&gBinderFd);
+
+    if (gBinderFd >= 0) {
+        if (healthd_register_event(gBinderFd, binder_event))
+            KLOG_ERROR(LOG_TAG,
+                       "Register for binder events failed\n");
+    }
+
+    gBatteryPropertiesRegistrar = new BatteryPropertiesRegistrar();
+    gBatteryPropertiesRegistrar->publish();
+}
diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp
new file mode 100644
index 0000000..394feb8
--- /dev/null
+++ b/healthd/healthd_mode_charger.cpp
@@ -0,0 +1,720 @@
+/*
+ * Copyright (C) 2011-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 <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <linux/input.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/epoll.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <sys/socket.h>
+#include <linux/netlink.h>
+
+#include <batteryservice/BatteryService.h>
+#include <cutils/android_reboot.h>
+#include <cutils/klog.h>
+#include <cutils/misc.h>
+#include <cutils/uevent.h>
+#include <cutils/properties.h>
+
+#ifdef CHARGER_ENABLE_SUSPEND
+#include <suspend/autosuspend.h>
+#endif
+
+#include "minui/minui.h"
+
+#include "healthd.h"
+
+char *locale;
+
+#ifndef max
+#define max(a,b) ((a) > (b) ? (a) : (b))
+#endif
+
+#ifndef min
+#define min(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+#define ARRAY_SIZE(x)           (sizeof(x)/sizeof(x[0]))
+
+#define MSEC_PER_SEC            (1000LL)
+#define NSEC_PER_MSEC           (1000000LL)
+
+#define BATTERY_UNKNOWN_TIME    (2 * MSEC_PER_SEC)
+#define POWER_ON_KEY_TIME       (2 * MSEC_PER_SEC)
+#define UNPLUGGED_SHUTDOWN_TIME (10 * MSEC_PER_SEC)
+
+#define BATTERY_FULL_THRESH     95
+#define SCREEN_ON_BATTERY_THRESH 0
+
+#define LAST_KMSG_PATH          "/proc/last_kmsg"
+#define LAST_KMSG_PSTORE_PATH   "/sys/fs/pstore/console-ramoops"
+#define LAST_KMSG_MAX_SZ        (32 * 1024)
+
+#define LOGE(x...) do { KLOG_ERROR("charger", x); } while (0)
+#define LOGI(x...) do { KLOG_INFO("charger", x); } while (0)
+#define LOGV(x...) do { KLOG_DEBUG("charger", x); } while (0)
+
+struct key_state {
+    bool pending;
+    bool down;
+    int64_t timestamp;
+};
+
+struct frame {
+    int disp_time;
+    int min_capacity;
+    bool level_only;
+
+    gr_surface surface;
+};
+
+struct animation {
+    bool run;
+
+    struct frame *frames;
+    int cur_frame;
+    int num_frames;
+
+    int cur_cycle;
+    int num_cycles;
+
+    /* current capacity being animated */
+    int capacity;
+};
+
+struct charger {
+    bool have_battery_state;
+    bool charger_connected;
+    int capacity;
+    int64_t next_screen_transition;
+    int64_t next_key_check;
+    int64_t next_pwr_check;
+
+    struct key_state keys[KEY_MAX + 1];
+
+    struct animation *batt_anim;
+    gr_surface surf_unknown;
+};
+
+static struct frame batt_anim_frames[] = {
+    {
+        .disp_time = 750,
+        .min_capacity = 0,
+        .level_only = false,
+        .surface = NULL,
+    },
+    {
+        .disp_time = 750,
+        .min_capacity = 20,
+        .level_only = false,
+        .surface = NULL,
+    },
+    {
+        .disp_time = 750,
+        .min_capacity = 40,
+        .level_only = false,
+        .surface = NULL,
+    },
+    {
+        .disp_time = 750,
+        .min_capacity = 60,
+        .level_only = false,
+        .surface = NULL,
+    },
+    {
+        .disp_time = 750,
+        .min_capacity = 80,
+        .level_only = true,
+        .surface = NULL,
+    },
+    {
+        .disp_time = 750,
+        .min_capacity = BATTERY_FULL_THRESH,
+        .level_only = false,
+        .surface = NULL,
+    },
+};
+
+static struct animation battery_animation = {
+    .run = false,
+    .frames = batt_anim_frames,
+    .cur_frame = 0,
+    .num_frames = ARRAY_SIZE(batt_anim_frames),
+    .cur_cycle = 0,
+    .num_cycles = 3,
+    .capacity = 0,
+};
+
+static struct charger charger_state;
+
+static int char_width;
+static int char_height;
+static bool minui_inited;
+
+/* current time in milliseconds */
+static int64_t curr_time_ms(void)
+{
+    struct timespec tm;
+    clock_gettime(CLOCK_MONOTONIC, &tm);
+    return tm.tv_sec * MSEC_PER_SEC + (tm.tv_nsec / NSEC_PER_MSEC);
+}
+
+static void clear_screen(void)
+{
+    gr_color(0, 0, 0, 255);
+    gr_clear();
+}
+
+#define MAX_KLOG_WRITE_BUF_SZ 256
+
+static void dump_last_kmsg(void)
+{
+    char *buf;
+    char *ptr;
+    unsigned sz = 0;
+    int len;
+
+    LOGI("\n");
+    LOGI("*************** LAST KMSG ***************\n");
+    LOGI("\n");
+    buf = (char *)load_file(LAST_KMSG_PSTORE_PATH, &sz);
+
+    if (!buf || !sz) {
+        buf = (char *)load_file(LAST_KMSG_PATH, &sz);
+        if (!buf || !sz) {
+            LOGI("last_kmsg not found. Cold reset?\n");
+            goto out;
+        }
+    }
+
+    len = min(sz, LAST_KMSG_MAX_SZ);
+    ptr = buf + (sz - len);
+
+    while (len > 0) {
+        int cnt = min(len, MAX_KLOG_WRITE_BUF_SZ);
+        char yoink;
+        char *nl;
+
+        nl = (char *)memrchr(ptr, '\n', cnt - 1);
+        if (nl)
+            cnt = nl - ptr + 1;
+
+        yoink = ptr[cnt];
+        ptr[cnt] = '\0';
+        klog_write(6, "<6>%s", ptr);
+        ptr[cnt] = yoink;
+
+        len -= cnt;
+        ptr += cnt;
+    }
+
+    free(buf);
+
+out:
+    LOGI("\n");
+    LOGI("************* END LAST KMSG *************\n");
+    LOGI("\n");
+}
+
+static int get_battery_capacity()
+{
+    return charger_state.capacity;
+}
+
+#ifdef CHARGER_ENABLE_SUSPEND
+static int request_suspend(bool enable)
+{
+    if (enable)
+        return autosuspend_enable();
+    else
+        return autosuspend_disable();
+}
+#else
+static int request_suspend(bool /*enable*/)
+{
+    return 0;
+}
+#endif
+
+static int draw_text(const char *str, int x, int y)
+{
+    int str_len_px = gr_measure(str);
+
+    if (x < 0)
+        x = (gr_fb_width() - str_len_px) / 2;
+    if (y < 0)
+        y = (gr_fb_height() - char_height) / 2;
+    gr_text(x, y, str, 0);
+
+    return y + char_height;
+}
+
+static void android_green(void)
+{
+    gr_color(0xa4, 0xc6, 0x39, 255);
+}
+
+/* returns the last y-offset of where the surface ends */
+static int draw_surface_centered(struct charger* /*charger*/, gr_surface surface)
+{
+    int w;
+    int h;
+    int x;
+    int y;
+
+    w = gr_get_width(surface);
+    h = gr_get_height(surface);
+    x = (gr_fb_width() - w) / 2 ;
+    y = (gr_fb_height() - h) / 2 ;
+
+    LOGV("drawing surface %dx%d+%d+%d\n", w, h, x, y);
+    gr_blit(surface, 0, 0, w, h, x, y);
+    return y + h;
+}
+
+static void draw_unknown(struct charger *charger)
+{
+    int y;
+    if (charger->surf_unknown) {
+        draw_surface_centered(charger, charger->surf_unknown);
+    } else {
+        android_green();
+        y = draw_text("Charging!", -1, -1);
+        draw_text("?\?/100", -1, y + 25);
+    }
+}
+
+static void draw_battery(struct charger *charger)
+{
+    struct animation *batt_anim = charger->batt_anim;
+    struct frame *frame = &batt_anim->frames[batt_anim->cur_frame];
+
+    if (batt_anim->num_frames != 0) {
+        draw_surface_centered(charger, frame->surface);
+        LOGV("drawing frame #%d min_cap=%d time=%d\n",
+             batt_anim->cur_frame, frame->min_capacity,
+             frame->disp_time);
+    }
+}
+
+static void redraw_screen(struct charger *charger)
+{
+    struct animation *batt_anim = charger->batt_anim;
+
+    clear_screen();
+
+    /* try to display *something* */
+    if (batt_anim->capacity < 0 || batt_anim->num_frames == 0)
+        draw_unknown(charger);
+    else
+        draw_battery(charger);
+    gr_flip();
+}
+
+static void kick_animation(struct animation *anim)
+{
+    anim->run = true;
+}
+
+static void reset_animation(struct animation *anim)
+{
+    anim->cur_cycle = 0;
+    anim->cur_frame = 0;
+    anim->run = false;
+}
+
+static void update_screen_state(struct charger *charger, int64_t now)
+{
+    struct animation *batt_anim = charger->batt_anim;
+    int cur_frame;
+    int disp_time;
+
+    if (!batt_anim->run || now < charger->next_screen_transition)
+        return;
+
+    if (!minui_inited) {
+        int batt_cap = get_battery_capacity();
+
+        if (batt_cap < SCREEN_ON_BATTERY_THRESH) {
+            LOGV("[%" PRId64 "] level %d, leave screen off\n", now, batt_cap);
+            batt_anim->run = false;
+            charger->next_screen_transition = -1;
+            if (charger->charger_connected)
+                request_suspend(true);
+            return;
+        }
+
+        gr_init();
+        gr_font_size(&char_width, &char_height);
+
+#ifndef CHARGER_DISABLE_INIT_BLANK
+        gr_fb_blank(true);
+#endif
+        minui_inited = true;
+    }
+
+    /* animation is over, blank screen and leave */
+    if (batt_anim->cur_cycle == batt_anim->num_cycles) {
+        reset_animation(batt_anim);
+        charger->next_screen_transition = -1;
+        gr_fb_blank(true);
+        LOGV("[%" PRId64 "] animation done\n", now);
+        if (charger->charger_connected)
+            request_suspend(true);
+        return;
+    }
+
+    disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time;
+
+    /* animation starting, set up the animation */
+    if (batt_anim->cur_frame == 0) {
+        int batt_cap;
+        int ret;
+
+        LOGV("[%" PRId64 "] animation starting\n", now);
+        batt_cap = get_battery_capacity();
+        if (batt_cap >= 0 && batt_anim->num_frames != 0) {
+            int i;
+
+            /* find first frame given current capacity */
+            for (i = 1; i < batt_anim->num_frames; i++) {
+                if (batt_cap < batt_anim->frames[i].min_capacity)
+                    break;
+            }
+            batt_anim->cur_frame = i - 1;
+
+            /* show the first frame for twice as long */
+            disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time * 2;
+        }
+
+        batt_anim->capacity = batt_cap;
+    }
+
+    /* unblank the screen  on first cycle */
+    if (batt_anim->cur_cycle == 0)
+        gr_fb_blank(false);
+
+    /* draw the new frame (@ cur_frame) */
+    redraw_screen(charger);
+
+    /* if we don't have anim frames, we only have one image, so just bump
+     * the cycle counter and exit
+     */
+    if (batt_anim->num_frames == 0 || batt_anim->capacity < 0) {
+        LOGV("[%" PRId64 "] animation missing or unknown battery status\n", now);
+        charger->next_screen_transition = now + BATTERY_UNKNOWN_TIME;
+        batt_anim->cur_cycle++;
+        return;
+    }
+
+    /* schedule next screen transition */
+    charger->next_screen_transition = now + disp_time;
+
+    /* advance frame cntr to the next valid frame only if we are charging
+     * if necessary, advance cycle cntr, and reset frame cntr
+     */
+    if (charger->charger_connected) {
+        batt_anim->cur_frame++;
+
+        /* if the frame is used for level-only, that is only show it when it's
+         * the current level, skip it during the animation.
+         */
+        while (batt_anim->cur_frame < batt_anim->num_frames &&
+               batt_anim->frames[batt_anim->cur_frame].level_only)
+            batt_anim->cur_frame++;
+        if (batt_anim->cur_frame >= batt_anim->num_frames) {
+            batt_anim->cur_cycle++;
+            batt_anim->cur_frame = 0;
+
+            /* don't reset the cycle counter, since we use that as a signal
+             * in a test above to check if animation is over
+             */
+        }
+    } else {
+        /* Stop animating if we're not charging.
+         * If we stop it immediately instead of going through this loop, then
+         * the animation would stop somewhere in the middle.
+         */
+        batt_anim->cur_frame = 0;
+        batt_anim->cur_cycle++;
+    }
+}
+
+static int set_key_callback(int code, int value, void *data)
+{
+    struct charger *charger = (struct charger *)data;
+    int64_t now = curr_time_ms();
+    int down = !!value;
+
+    if (code > KEY_MAX)
+        return -1;
+
+    /* ignore events that don't modify our state */
+    if (charger->keys[code].down == down)
+        return 0;
+
+    /* only record the down even timestamp, as the amount
+     * of time the key spent not being pressed is not useful */
+    if (down)
+        charger->keys[code].timestamp = now;
+    charger->keys[code].down = down;
+    charger->keys[code].pending = true;
+    if (down) {
+        LOGV("[%" PRId64 "] key[%d] down\n", now, code);
+    } else {
+        int64_t duration = now - charger->keys[code].timestamp;
+        int64_t secs = duration / 1000;
+        int64_t msecs = duration - secs * 1000;
+        LOGV("[%" PRId64 "] key[%d] up (was down for %" PRId64 ".%" PRId64 "sec)\n",
+             now, code, secs, msecs);
+    }
+
+    return 0;
+}
+
+static void update_input_state(struct charger *charger,
+                               struct input_event *ev)
+{
+    if (ev->type != EV_KEY)
+        return;
+    set_key_callback(ev->code, ev->value, charger);
+}
+
+static void set_next_key_check(struct charger *charger,
+                               struct key_state *key,
+                               int64_t timeout)
+{
+    int64_t then = key->timestamp + timeout;
+
+    if (charger->next_key_check == -1 || then < charger->next_key_check)
+        charger->next_key_check = then;
+}
+
+static void process_key(struct charger *charger, int code, int64_t now)
+{
+    struct key_state *key = &charger->keys[code];
+    int64_t next_key_check;
+
+    if (code == KEY_POWER) {
+        if (key->down) {
+            int64_t reboot_timeout = key->timestamp + POWER_ON_KEY_TIME;
+            if (now >= reboot_timeout) {
+                /* We do not currently support booting from charger mode on
+                   all devices. Check the property and continue booting or reboot
+                   accordingly. */
+                if (property_get_bool("ro.enable_boot_charger_mode", false)) {
+                    LOGI("[%" PRId64 "] booting from charger mode\n", now);
+                    property_set("sys.boot_from_charger_mode", "1");
+                } else {
+                    LOGI("[%" PRId64 "] rebooting\n", now);
+                    android_reboot(ANDROID_RB_RESTART, 0, 0);
+                }
+            } else {
+                /* if the key is pressed but timeout hasn't expired,
+                 * make sure we wake up at the right-ish time to check
+                 */
+                set_next_key_check(charger, key, POWER_ON_KEY_TIME);
+            }
+        } else {
+            /* if the power key got released, force screen state cycle */
+            if (key->pending) {
+                request_suspend(false);
+                kick_animation(charger->batt_anim);
+            }
+        }
+    }
+
+    key->pending = false;
+}
+
+static void handle_input_state(struct charger *charger, int64_t now)
+{
+    process_key(charger, KEY_POWER, now);
+
+    if (charger->next_key_check != -1 && now > charger->next_key_check)
+        charger->next_key_check = -1;
+}
+
+static void handle_power_supply_state(struct charger *charger, int64_t now)
+{
+    if (!charger->have_battery_state)
+        return;
+
+    if (!charger->charger_connected) {
+        request_suspend(false);
+        if (charger->next_pwr_check == -1) {
+            charger->next_pwr_check = now + UNPLUGGED_SHUTDOWN_TIME;
+            LOGI("[%" PRId64 "] device unplugged: shutting down in %" PRId64 " (@ %" PRId64 ")\n",
+                 now, (int64_t)UNPLUGGED_SHUTDOWN_TIME, charger->next_pwr_check);
+        } else if (now >= charger->next_pwr_check) {
+            LOGI("[%" PRId64 "] shutting down\n", now);
+            android_reboot(ANDROID_RB_POWEROFF, 0, 0);
+        } else {
+            /* otherwise we already have a shutdown timer scheduled */
+        }
+    } else {
+        /* online supply present, reset shutdown timer if set */
+        if (charger->next_pwr_check != -1) {
+            LOGI("[%" PRId64 "] device plugged in: shutdown cancelled\n", now);
+            kick_animation(charger->batt_anim);
+        }
+        charger->next_pwr_check = -1;
+    }
+}
+
+void healthd_mode_charger_heartbeat()
+{
+    struct charger *charger = &charger_state;
+    int64_t now = curr_time_ms();
+    int ret;
+
+    handle_input_state(charger, now);
+    handle_power_supply_state(charger, now);
+
+    /* do screen update last in case any of the above want to start
+     * screen transitions (animations, etc)
+     */
+    update_screen_state(charger, now);
+}
+
+void healthd_mode_charger_battery_update(
+    struct android::BatteryProperties *props)
+{
+    struct charger *charger = &charger_state;
+
+    charger->charger_connected =
+        props->chargerAcOnline || props->chargerUsbOnline ||
+        props->chargerWirelessOnline;
+    charger->capacity = props->batteryLevel;
+
+    if (!charger->have_battery_state) {
+        charger->have_battery_state = true;
+        charger->next_screen_transition = curr_time_ms() - 1;
+        reset_animation(charger->batt_anim);
+        kick_animation(charger->batt_anim);
+    }
+}
+
+int healthd_mode_charger_preparetowait(void)
+{
+    struct charger *charger = &charger_state;
+    int64_t now = curr_time_ms();
+    int64_t next_event = INT64_MAX;
+    int64_t timeout;
+    struct input_event ev;
+    int ret;
+
+    LOGV("[%" PRId64 "] next screen: %" PRId64 " next key: %" PRId64 " next pwr: %" PRId64 "\n", now,
+         charger->next_screen_transition, charger->next_key_check,
+         charger->next_pwr_check);
+
+    if (charger->next_screen_transition != -1)
+        next_event = charger->next_screen_transition;
+    if (charger->next_key_check != -1 && charger->next_key_check < next_event)
+        next_event = charger->next_key_check;
+    if (charger->next_pwr_check != -1 && charger->next_pwr_check < next_event)
+        next_event = charger->next_pwr_check;
+
+    if (next_event != -1 && next_event != INT64_MAX)
+        timeout = max(0, next_event - now);
+    else
+        timeout = -1;
+
+   return (int)timeout;
+}
+
+static int input_callback(int fd, unsigned int epevents, void *data)
+{
+    struct charger *charger = (struct charger *)data;
+    struct input_event ev;
+    int ret;
+
+    ret = ev_get_input(fd, epevents, &ev);
+    if (ret)
+        return -1;
+    update_input_state(charger, &ev);
+    return 0;
+}
+
+static void charger_event_handler(uint32_t /*epevents*/)
+{
+    int ret;
+
+    ret = ev_wait(-1);
+    if (!ret)
+        ev_dispatch();
+}
+
+void healthd_mode_charger_init(struct healthd_config* /*config*/)
+{
+    int ret;
+    struct charger *charger = &charger_state;
+    int i;
+    int epollfd;
+
+    dump_last_kmsg();
+
+    LOGI("--------------- STARTING CHARGER MODE ---------------\n");
+
+    ret = ev_init(input_callback, charger);
+    if (!ret) {
+        epollfd = ev_get_epollfd();
+        healthd_register_event(epollfd, charger_event_handler);
+    }
+
+    ret = res_create_display_surface("charger/battery_fail", &charger->surf_unknown);
+    if (ret < 0) {
+        LOGE("Cannot load battery_fail image\n");
+        charger->surf_unknown = NULL;
+    }
+
+    charger->batt_anim = &battery_animation;
+
+    gr_surface* scale_frames;
+    int scale_count;
+    ret = res_create_multi_display_surface("charger/battery_scale", &scale_count, &scale_frames);
+    if (ret < 0) {
+        LOGE("Cannot load battery_scale image\n");
+        charger->batt_anim->num_frames = 0;
+        charger->batt_anim->num_cycles = 1;
+    } else if (scale_count != charger->batt_anim->num_frames) {
+        LOGE("battery_scale image has unexpected frame count (%d, expected %d)\n",
+             scale_count, charger->batt_anim->num_frames);
+        charger->batt_anim->num_frames = 0;
+        charger->batt_anim->num_cycles = 1;
+    } else {
+        for (i = 0; i < charger->batt_anim->num_frames; i++) {
+            charger->batt_anim->frames[i].surface = scale_frames[i];
+        }
+    }
+
+    ev_sync_key_state(set_key_callback, charger);
+
+    charger->next_screen_transition = -1;
+    charger->next_key_check = -1;
+    charger->next_pwr_check = -1;
+}
diff --git a/charger/images/battery_fail.png b/healthd/images/battery_fail.png
similarity index 100%
rename from charger/images/battery_fail.png
rename to healthd/images/battery_fail.png
Binary files differ
diff --git a/charger/images/battery_scale.png b/healthd/images/battery_scale.png
similarity index 100%
rename from charger/images/battery_scale.png
rename to healthd/images/battery_scale.png
Binary files differ
diff --git a/include/backtrace/BacktraceMap.h b/include/backtrace/BacktraceMap.h
index c717f09..4ed23a8 100644
--- a/include/backtrace/BacktraceMap.h
+++ b/include/backtrace/BacktraceMap.h
@@ -41,7 +41,10 @@
 
 class BacktraceMap {
 public:
-  static BacktraceMap* Create(pid_t pid);
+  // If uncached is true, then parse the current process map as of the call.
+  // Passing a map created with uncached set to true to Backtrace::Create()
+  // is unsupported.
+  static BacktraceMap* Create(pid_t pid, bool uncached = false);
 
   virtual ~BacktraceMap();
 
diff --git a/include/cutils/atomic-arm.h b/include/cutils/atomic-arm.h
index 172a0cd..6b031b6 100644
--- a/include/cutils/atomic-arm.h
+++ b/include/cutils/atomic-arm.h
@@ -37,15 +37,6 @@
 #endif
 }
 
-extern ANDROID_ATOMIC_INLINE void android_memory_store_barrier()
-{
-#if ANDROID_SMP == 0
-    android_compiler_barrier();
-#else
-    __asm__ __volatile__ ("dmb st" : : : "memory");
-#endif
-}
-
 extern ANDROID_ATOMIC_INLINE
 int32_t android_atomic_acquire_load(volatile const int32_t *ptr)
 {
diff --git a/include/cutils/atomic-arm64.h b/include/cutils/atomic-arm64.h
index 4562ad0..7ae47d7 100644
--- a/include/cutils/atomic-arm64.h
+++ b/include/cutils/atomic-arm64.h
@@ -46,29 +46,11 @@
     __asm__ __volatile__ ("" : : : "memory");
 }
 
-#if ANDROID_SMP == 0
-extern ANDROID_ATOMIC_INLINE
-void android_memory_barrier(void)
-{
-    android_compiler_barrier();
-}
-extern ANDROID_ATOMIC_INLINE
-void android_memory_store_barrier(void)
-{
-    android_compiler_barrier();
-}
-#else
 extern ANDROID_ATOMIC_INLINE
 void android_memory_barrier(void)
 {
     __asm__ __volatile__ ("dmb ish" : : : "memory");
 }
-extern ANDROID_ATOMIC_INLINE
-void android_memory_store_barrier(void)
-{
-    __asm__ __volatile__ ("dmb ishst" : : : "memory");
-}
-#endif
 
 extern ANDROID_ATOMIC_INLINE
 int32_t android_atomic_acquire_load(volatile const int32_t *ptr)
@@ -79,14 +61,6 @@
 }
 
 extern ANDROID_ATOMIC_INLINE
-int64_t android_atomic_acquire_load64(volatile const int64_t *ptr)
-{
-    int64_t value = *ptr;
-    android_memory_barrier();
-    return value;
-}
-
-extern ANDROID_ATOMIC_INLINE
 int32_t android_atomic_release_load(volatile const int32_t *ptr)
 {
     android_memory_barrier();
@@ -94,13 +68,6 @@
 }
 
 extern ANDROID_ATOMIC_INLINE
-int64_t android_atomic_release_load64(volatile const int64_t *ptr)
-{
-    android_memory_barrier();
-    return *ptr;
-}
-
-extern ANDROID_ATOMIC_INLINE
 void android_atomic_acquire_store(int32_t value, volatile int32_t *ptr)
 {
     *ptr = value;
@@ -108,13 +75,6 @@
 }
 
 extern ANDROID_ATOMIC_INLINE
-void android_atomic_acquire_store64(int64_t value, volatile int64_t *ptr)
-{
-    *ptr = value;
-    android_memory_barrier();
-}
-
-extern ANDROID_ATOMIC_INLINE
 void android_atomic_release_store(int32_t value, volatile int32_t *ptr)
 {
     android_memory_barrier();
@@ -122,13 +82,6 @@
 }
 
 extern ANDROID_ATOMIC_INLINE
-void android_atomic_release_store64(int64_t value, volatile int64_t *ptr)
-{
-    android_memory_barrier();
-    *ptr = value;
-}
-
-extern ANDROID_ATOMIC_INLINE
 int android_atomic_cas(int32_t old_value, int32_t new_value,
                        volatile int32_t *ptr)
 {
@@ -136,13 +89,6 @@
 }
 
 extern ANDROID_ATOMIC_INLINE
-int64_t android_atomic_cas64(int64_t old_value, int64_t new_value,
-                             volatile int64_t *ptr)
-{
-    return __sync_val_compare_and_swap(ptr, old_value, new_value) != old_value;
-}
-
-extern ANDROID_ATOMIC_INLINE
 int android_atomic_acquire_cas(int32_t old_value, int32_t new_value,
                                volatile int32_t *ptr)
 {
@@ -152,15 +98,6 @@
 }
 
 extern ANDROID_ATOMIC_INLINE
-int64_t android_atomic_acquire_cas64(int64_t old_value, int64_t new_value,
-                                     volatile int64_t *ptr)
-{
-    int status = android_atomic_cas64(old_value, new_value, ptr);
-    android_memory_barrier();
-    return status;
-}
-
-extern ANDROID_ATOMIC_INLINE
 int android_atomic_release_cas(int32_t old_value, int32_t new_value,
                                volatile int32_t *ptr)
 {
@@ -169,14 +106,6 @@
 }
 
 extern ANDROID_ATOMIC_INLINE
-int64_t android_atomic_release_cas64(int64_t old_value, int64_t new_value,
-                                     volatile int64_t *ptr)
-{
-    android_memory_barrier();
-    return android_atomic_cas64(old_value, new_value, ptr);
-}
-
-extern ANDROID_ATOMIC_INLINE
 int32_t android_atomic_add(int32_t increment, volatile int32_t *ptr)
 {
     int32_t prev, status;
diff --git a/include/cutils/atomic-inline.h b/include/cutils/atomic-inline.h
index 007a905..a31e913 100644
--- a/include/cutils/atomic-inline.h
+++ b/include/cutils/atomic-inline.h
@@ -65,12 +65,6 @@
 #define ANDROID_MEMBAR_FULL android_memory_barrier
 #endif
 
-#if ANDROID_SMP == 0
-#define ANDROID_MEMBAR_STORE android_compiler_barrier
-#else
-#define ANDROID_MEMBAR_STORE android_memory_store_barrier
-#endif
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/cutils/atomic-mips.h b/include/cutils/atomic-mips.h
index 1ed833d..5d4f097 100644
--- a/include/cutils/atomic-mips.h
+++ b/include/cutils/atomic-mips.h
@@ -33,19 +33,11 @@
 {
     android_compiler_barrier();
 }
-extern ANDROID_ATOMIC_INLINE void android_memory_store_barrier(void)
-{
-    android_compiler_barrier();
-}
 #else
 extern ANDROID_ATOMIC_INLINE void android_memory_barrier(void)
 {
     __asm__ __volatile__ ("sync" : : : "memory");
 }
-extern ANDROID_ATOMIC_INLINE void android_memory_store_barrier(void)
-{
-    __asm__ __volatile__ ("sync" : : : "memory");
-}
 #endif
 
 extern ANDROID_ATOMIC_INLINE int32_t
diff --git a/include/cutils/atomic-mips64.h b/include/cutils/atomic-mips64.h
index 99bbe3a..9d8f65e 100644
--- a/include/cutils/atomic-mips64.h
+++ b/include/cutils/atomic-mips64.h
@@ -28,25 +28,10 @@
     __asm__ __volatile__ ("" : : : "memory");
 }
 
-#if ANDROID_SMP == 0
-extern ANDROID_ATOMIC_INLINE void android_memory_barrier(void)
-{
-    android_compiler_barrier();
-}
-extern ANDROID_ATOMIC_INLINE void android_memory_store_barrier(void)
-{
-    android_compiler_barrier();
-}
-#else
 extern ANDROID_ATOMIC_INLINE void android_memory_barrier(void)
 {
     __asm__ __volatile__ ("sync" : : : "memory");
 }
-extern ANDROID_ATOMIC_INLINE void android_memory_store_barrier(void)
-{
-    __asm__ __volatile__ ("sync" : : : "memory");
-}
-#endif
 
 extern ANDROID_ATOMIC_INLINE
 int32_t android_atomic_acquire_load(volatile const int32_t *ptr)
@@ -57,14 +42,6 @@
 }
 
 extern ANDROID_ATOMIC_INLINE
-int64_t android_atomic_acquire_load64(volatile const int64_t *ptr)
-{
-    int64_t value = *ptr;
-    android_memory_barrier();
-    return value;
-}
-
-extern ANDROID_ATOMIC_INLINE
 int32_t android_atomic_release_load(volatile const int32_t *ptr)
 {
     android_memory_barrier();
@@ -72,13 +49,6 @@
 }
 
 extern ANDROID_ATOMIC_INLINE
-int64_t android_atomic_release_load64(volatile const int64_t *ptr)
-{
-    android_memory_barrier();
-    return *ptr;
-}
-
-extern ANDROID_ATOMIC_INLINE
 void android_atomic_acquire_store(int32_t value, volatile int32_t *ptr)
 {
     *ptr = value;
@@ -86,13 +56,6 @@
 }
 
 extern ANDROID_ATOMIC_INLINE
-void android_atomic_acquire_store64(int64_t value, volatile int64_t *ptr)
-{
-    *ptr = value;
-    android_memory_barrier();
-}
-
-extern ANDROID_ATOMIC_INLINE
 void android_atomic_release_store(int32_t value, volatile int32_t *ptr)
 {
     android_memory_barrier();
@@ -100,13 +63,6 @@
 }
 
 extern ANDROID_ATOMIC_INLINE
-void android_atomic_release_store64(int64_t value, volatile int64_t *ptr)
-{
-    android_memory_barrier();
-    *ptr = value;
-}
-
-extern ANDROID_ATOMIC_INLINE
 int android_atomic_cas(int32_t old_value, int32_t new_value, volatile int32_t *ptr)
 {
     int32_t prev, status;
@@ -126,13 +82,6 @@
 }
 
 extern ANDROID_ATOMIC_INLINE
-int64_t android_atomic_cas64(int64_t old_value, int64_t new_value,
-                             volatile int64_t *ptr)
-{
-    return __sync_val_compare_and_swap(ptr, old_value, new_value) != old_value;
-}
-
-extern ANDROID_ATOMIC_INLINE
 int android_atomic_acquire_cas(int32_t old_value,
                            int32_t new_value,
                            volatile int32_t *ptr)
@@ -143,15 +92,6 @@
 }
 
 extern ANDROID_ATOMIC_INLINE
-int64_t android_atomic_acquire_cas64(int64_t old_value, int64_t new_value,
-                                     volatile int64_t *ptr)
-{
-    int status = android_atomic_cas64(old_value, new_value, ptr);
-    android_memory_barrier();
-    return status;
-}
-
-extern ANDROID_ATOMIC_INLINE
 int android_atomic_release_cas(int32_t old_value,
                            int32_t new_value,
                            volatile int32_t *ptr)
@@ -161,14 +101,6 @@
 }
 
 extern ANDROID_ATOMIC_INLINE
-int64_t android_atomic_release_cas64(int64_t old_value, int64_t new_value,
-                                     volatile int64_t *ptr)
-{
-    android_memory_barrier();
-    return android_atomic_cas64(old_value, new_value, ptr);
-}
-
-extern ANDROID_ATOMIC_INLINE
 int32_t android_atomic_add(int32_t increment, volatile int32_t *ptr)
 {
     int32_t prev, status;
diff --git a/include/cutils/atomic-x86.h b/include/cutils/atomic-x86.h
index 9480f57..06bf1a3 100644
--- a/include/cutils/atomic-x86.h
+++ b/include/cutils/atomic-x86.h
@@ -33,19 +33,11 @@
 {
     android_compiler_barrier();
 }
-extern ANDROID_ATOMIC_INLINE void android_memory_store_barrier(void)
-{
-    android_compiler_barrier();
-}
 #else
 extern ANDROID_ATOMIC_INLINE void android_memory_barrier(void)
 {
     __asm__ __volatile__ ("mfence" : : : "memory");
 }
-extern ANDROID_ATOMIC_INLINE void android_memory_store_barrier(void)
-{
-    android_compiler_barrier();
-}
 #endif
 
 extern ANDROID_ATOMIC_INLINE int32_t
diff --git a/include/cutils/atomic-x86_64.h b/include/cutils/atomic-x86_64.h
index 5b5c203..99cb070 100644
--- a/include/cutils/atomic-x86_64.h
+++ b/include/cutils/atomic-x86_64.h
@@ -41,29 +41,11 @@
     __asm__ __volatile__ ("" : : : "memory");
 }
 
-#if ANDROID_SMP == 0
-extern ANDROID_ATOMIC_INLINE
-void android_memory_barrier(void)
-{
-    android_compiler_barrier();
-}
-extern ANDROID_ATOMIC_INLINE
-void android_memory_store_barrier(void)
-{
-    android_compiler_barrier();
-}
-#else
 extern ANDROID_ATOMIC_INLINE
 void android_memory_barrier(void)
 {
     __asm__ __volatile__ ("mfence" : : : "memory");
 }
-extern ANDROID_ATOMIC_INLINE
-void android_memory_store_barrier(void)
-{
-    android_compiler_barrier();
-}
-#endif
 
 extern ANDROID_ATOMIC_INLINE
 int32_t android_atomic_acquire_load(volatile const int32_t *ptr)
@@ -74,14 +56,6 @@
 }
 
 extern ANDROID_ATOMIC_INLINE
-int64_t android_atomic_acquire_load64(volatile const int64_t *ptr)
-{
-    int64_t value = *ptr;
-    android_compiler_barrier();
-    return value;
-}
-
-extern ANDROID_ATOMIC_INLINE
 int32_t android_atomic_release_load(volatile const int32_t *ptr)
 {
     android_memory_barrier();
@@ -89,13 +63,6 @@
 }
 
 extern ANDROID_ATOMIC_INLINE
-int64_t android_atomic_release_load64(volatile const int64_t *ptr)
-{
-    android_memory_barrier();
-    return *ptr;
-}
-
-extern ANDROID_ATOMIC_INLINE
 void android_atomic_acquire_store(int32_t value, volatile int32_t *ptr)
 {
     *ptr = value;
@@ -103,13 +70,6 @@
 }
 
 extern ANDROID_ATOMIC_INLINE
-void android_atomic_acquire_store64(int64_t value, volatile int64_t *ptr)
-{
-    *ptr = value;
-    android_memory_barrier();
-}
-
-extern ANDROID_ATOMIC_INLINE
 void android_atomic_release_store(int32_t value, volatile int32_t *ptr)
 {
     android_compiler_barrier();
@@ -117,13 +77,6 @@
 }
 
 extern ANDROID_ATOMIC_INLINE
-void android_atomic_release_store64(int64_t value, volatile int64_t *ptr)
-{
-    android_compiler_barrier();
-    *ptr = value;
-}
-
-extern ANDROID_ATOMIC_INLINE
 int android_atomic_cas(int32_t old_value, int32_t new_value,
                        volatile int32_t *ptr)
 {
@@ -136,18 +89,6 @@
 }
 
 extern ANDROID_ATOMIC_INLINE
-int64_t android_atomic_cas64(int64_t old_value, int64_t new_value,
-                             volatile int64_t *ptr)
-{
-    int64_t prev;
-    __asm__ __volatile__ ("lock; cmpxchgq %1, %2"
-                          : "=a" (prev)
-                          : "q" (new_value), "m" (*ptr), "0" (old_value)
-                          : "memory");
-    return prev != old_value;
-}
-
-extern ANDROID_ATOMIC_INLINE
 int android_atomic_acquire_cas(int32_t old_value, int32_t new_value,
                                volatile int32_t *ptr)
 {
@@ -156,14 +97,6 @@
 }
 
 extern ANDROID_ATOMIC_INLINE
-int64_t android_atomic_acquire_cas64(int64_t old_value, int64_t new_value,
-                                     volatile int64_t *ptr)
-{
-    /* Loads are not reordered with other loads. */
-    return android_atomic_cas64(old_value, new_value, ptr);
-}
-
-extern ANDROID_ATOMIC_INLINE
 int android_atomic_release_cas(int32_t old_value, int32_t new_value,
                                volatile int32_t *ptr)
 {
@@ -172,14 +105,6 @@
 }
 
 extern ANDROID_ATOMIC_INLINE
-int64_t android_atomic_release_cas64(int64_t old_value, int64_t new_value,
-                                     volatile int64_t *ptr)
-{
-    /* Stores are not reordered with other stores. */
-    return android_atomic_cas64(old_value, new_value, ptr);
-}
-
-extern ANDROID_ATOMIC_INLINE
 int32_t android_atomic_add(int32_t increment, volatile int32_t *ptr)
 {
     __asm__ __volatile__ ("lock; xaddl %0, %1"
diff --git a/include/cutils/atomic.h b/include/cutils/atomic.h
index 1787e34..79409a7 100644
--- a/include/cutils/atomic.h
+++ b/include/cutils/atomic.h
@@ -25,8 +25,20 @@
 #endif
 
 /*
- * A handful of basic atomic operations.  The appropriate pthread
- * functions should be used instead of these whenever possible.
+ * A handful of basic atomic operations.
+ * THESE ARE HERE FOR LEGACY REASONS ONLY.  AVOID.
+ *
+ * PREFERRED ALTERNATIVES:
+ * - Use C++/C/pthread locks/mutexes whenever there is not a
+ *   convincing reason to do otherwise.  Note that very clever and
+ *   complicated, but correct, lock-free code is often slower than
+ *   using locks, especially where nontrivial data structures
+ *   are involved.
+ * - C11 stdatomic.h.
+ * - Where supported, C++11 std::atomic<T> .
+ *
+ * PLEASE STOP READING HERE UNLESS YOU ARE TRYING TO UNDERSTAND
+ * OR UPDATE OLD CODE.
  *
  * The "acquire" and "release" terms can be defined intuitively in terms
  * of the placement of memory barriers in a simple lock implementation:
@@ -74,31 +86,40 @@
 /*
  * Perform an atomic load with "acquire" or "release" ordering.
  *
+ * Note that the notion of a "release" ordering for a load does not
+ * really fit into the C11 or C++11 memory model.  The extra ordering
+ * is normally observable only by code using memory_order_relaxed
+ * atomics, or data races.  In the rare cases in which such ordering
+ * is called for, use memory_order_relaxed atomics and a leading
+ * atomic_thread_fence (typically with memory_order_acquire,
+ * not memory_order_release!) instead.  If you do not understand
+ * this comment, you are in the vast majority, and should not be
+ * using release loads or replacing them with anything other than
+ * locks or default sequentially consistent atomics.
+ *
  * This is only necessary if you need the memory barrier.  A 32-bit read
  * from a 32-bit aligned address is atomic on all supported platforms.
  */
 int32_t android_atomic_acquire_load(volatile const int32_t* addr);
 int32_t android_atomic_release_load(volatile const int32_t* addr);
 
-#if defined (__LP64__)
-int64_t android_atomic_acquire_load64(volatile const int64_t* addr);
-int64_t android_atomic_release_load64(volatile const int64_t* addr);
-#endif
-
 /*
  * Perform an atomic store with "acquire" or "release" ordering.
  *
+ * Note that the notion of a "acquire" ordering for a store does not
+ * really fit into the C11 or C++11 memory model.  The extra ordering
+ * is normally observable only by code using memory_order_relaxed
+ * atomics, or data races.  In the rare cases in which such ordering
+ * is called for, use memory_order_relaxed atomics and a trailing
+ * atomic_thread_fence (typically with memory_order_release,
+ * not memory_order_acquire!) instead.
+ *
  * This is only necessary if you need the memory barrier.  A 32-bit write
  * to a 32-bit aligned address is atomic on all supported platforms.
  */
 void android_atomic_acquire_store(int32_t value, volatile int32_t* addr);
 void android_atomic_release_store(int32_t value, volatile int32_t* addr);
 
-#if defined (__LP64__)
-void android_atomic_acquire_store64(int64_t value, volatile int64_t* addr);
-void android_atomic_release_store64(int64_t value, volatile int64_t* addr);
-#endif
-
 /*
  * Compare-and-set operation with "acquire" or "release" ordering.
  *
@@ -116,13 +137,6 @@
 int android_atomic_release_cas(int32_t oldvalue, int32_t newvalue,
         volatile int32_t* addr);
 
-#if defined (__LP64__)
-int64_t android_atomic_acquire_cas64(int64_t old_value, int64_t new_value,
-        volatile int64_t *ptr);
-int64_t android_atomic_release_cas64(int64_t old_value, int64_t new_value,
-        volatile int64_t *ptr);
-#endif
-
 /*
  * Aliases for code using an older version of this header.  These are now
  * deprecated and should not be used.  The definitions will be removed
diff --git a/include/cutils/debugger.h b/include/cutils/debugger.h
index ae6bfc4..4bcc8e6 100644
--- a/include/cutils/debugger.h
+++ b/include/cutils/debugger.h
@@ -23,10 +23,13 @@
 extern "C" {
 #endif
 
-#if __LP64__
-#define DEBUGGER_SOCKET_NAME "android:debuggerd64"
+#define DEBUGGER32_SOCKET_NAME "android:debuggerd"
+#define DEBUGGER64_SOCKET_NAME "android:debuggerd64"
+
+#if defined(__LP64__)
+#define DEBUGGER_SOCKET_NAME DEBUGGER64_SOCKET_NAME
 #else
-#define DEBUGGER_SOCKET_NAME "android:debuggerd"
+#define DEBUGGER_SOCKET_NAME DEBUGGER32_SOCKET_NAME
 #endif
 
 typedef enum {
@@ -45,6 +48,16 @@
     int32_t original_si_code;
 } debugger_msg_t;
 
+#if defined(__LP64__)
+// For a 64 bit process to contact the 32 bit debuggerd.
+typedef struct {
+    debugger_action_t action;
+    pid_t tid;
+    uint32_t abort_msg_address;
+    int32_t original_si_code;
+} debugger32_msg_t;
+#endif
+
 /* Dumps a process backtrace, registers, and stack to a tombstone file (requires root).
  * Stores the tombstone path in the provided buffer.
  * Returns 0 on success, -1 on error.
diff --git a/include/cutils/jstring.h b/include/cutils/jstring.h
index ee0018f..a342608 100644
--- a/include/cutils/jstring.h
+++ b/include/cutils/jstring.h
@@ -24,7 +24,10 @@
 extern "C" {
 #endif
 
-typedef uint16_t char16_t;
+#if __STDC_VERSION__ < 201112L && __cplusplus < 201103L
+  typedef uint16_t char16_t;
+#endif
+  // otherwise char16_t is a keyword with the right semantics
 
 extern char * strndup16to8 (const char16_t* s, size_t n);
 extern size_t strnlen16to8 (const char16_t* s, size_t n);
diff --git a/include/cutils/klog.h b/include/cutils/klog.h
index 3635e89..d5ae6d7 100644
--- a/include/cutils/klog.h
+++ b/include/cutils/klog.h
@@ -25,7 +25,7 @@
 void klog_init(void);
 int  klog_get_level(void);
 void klog_set_level(int level);
-void klog_close(void);
+/* TODO: void klog_close(void); - and make klog_fd users thread safe. */
 void klog_write(int level, const char *fmt, ...)
     __attribute__ ((format(printf, 2, 3)));
 void klog_vwrite(int level, const char *fmt, va_list ap);
diff --git a/include/cutils/str_parms.h b/include/cutils/str_parms.h
index 247c996..66f3637 100644
--- a/include/cutils/str_parms.h
+++ b/include/cutils/str_parms.h
@@ -34,6 +34,12 @@
 int str_parms_add_float(struct str_parms *str_parms, const char *key,
                         float value);
 
+// Returns non-zero if the str_parms contains the specified key.
+int str_parms_has_key(struct str_parms *str_parms, const char *key);
+
+// Gets value associated with the specified key (if present), placing it in the buffer
+// pointed to by the out_val parameter.  Returns the length of the returned string value.
+// If 'key' isn't in the parms, then return -ENOENT (-2) and leave 'out_val' untouched.
 int str_parms_get_str(struct str_parms *str_parms, const char *key,
                       char *out_val, int len);
 int str_parms_get_int(struct str_parms *str_parms, const char *key,
diff --git a/include/cutils/trace.h b/include/cutils/trace.h
index fd9bc6a..fd24561 100644
--- a/include/cutils/trace.h
+++ b/include/cutils/trace.h
@@ -70,7 +70,8 @@
 #define ATRACE_TAG_DALVIK           (1<<14)
 #define ATRACE_TAG_RS               (1<<15)
 #define ATRACE_TAG_BIONIC           (1<<16)
-#define ATRACE_TAG_LAST             ATRACE_TAG_BIONIC
+#define ATRACE_TAG_POWER            (1<<17)
+#define ATRACE_TAG_LAST             ATRACE_TAG_POWER
 
 // Reserved for initialization.
 #define ATRACE_TAG_NOT_READY        (1LL<<63)
diff --git a/include/nativebridge/native_bridge.h b/include/nativebridge/native_bridge.h
new file mode 100644
index 0000000..ac254e9
--- /dev/null
+++ b/include/nativebridge/native_bridge.h
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2014 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 NATIVE_BRIDGE_H_
+#define NATIVE_BRIDGE_H_
+
+#include "jni.h"
+#include <stdint.h>
+#include <sys/types.h>
+
+namespace android {
+
+struct NativeBridgeRuntimeCallbacks;
+struct NativeBridgeRuntimeValues;
+
+// Open the native bridge, if any. Should be called by Runtime::Init(). A null library filename
+// signals that we do not want to load a native bridge.
+bool LoadNativeBridge(const char* native_bridge_library_filename,
+                      const NativeBridgeRuntimeCallbacks* runtime_callbacks);
+
+// Quick check whether a native bridge will be needed. This is based off of the instruction set
+// of the process.
+bool NeedsNativeBridge(const char* instruction_set);
+
+// Do the early initialization part of the native bridge, if necessary. This should be done under
+// high privileges.
+void PreInitializeNativeBridge(const char* app_data_dir, const char* instruction_set);
+
+// Initialize the native bridge, if any. Should be called by Runtime::DidForkFromZygote. The JNIEnv*
+// will be used to modify the app environment for the bridge.
+bool InitializeNativeBridge(JNIEnv* env, const char* instruction_set);
+
+// Unload the native bridge, if any. Should be called by Runtime::DidForkFromZygote.
+void UnloadNativeBridge();
+
+// Check whether a native bridge is available (opened or initialized). Requires a prior call to
+// LoadNativeBridge.
+bool NativeBridgeAvailable();
+
+// Check whether a native bridge is available (initialized). Requires a prior call to
+// LoadNativeBridge & InitializeNativeBridge.
+bool NativeBridgeInitialized();
+
+// Load a shared library that is supported by the native bridge.
+void* NativeBridgeLoadLibrary(const char* libpath, int flag);
+
+// Get a native bridge trampoline for specified native method.
+void* NativeBridgeGetTrampoline(void* handle, const char* name, const char* shorty, uint32_t len);
+
+// True if native library is valid and is for an ABI that is supported by native bridge.
+bool NativeBridgeIsSupported(const char* libpath);
+
+// Returns whether we have seen a native bridge error. This could happen because the library
+// was not found, rejected, could not be initialized and so on.
+//
+// This functionality is mainly for testing.
+bool NativeBridgeError();
+
+// Returns whether a given string is acceptable as a native bridge library filename.
+//
+// This functionality is exposed mainly for testing.
+bool NativeBridgeNameAcceptable(const char* native_bridge_library_filename);
+
+// Native bridge interfaces to runtime.
+struct NativeBridgeCallbacks {
+  // Version number of the interface.
+  uint32_t version;
+
+  // Initialize native bridge. Native bridge's internal implementation must ensure MT safety and
+  // that the native bridge is initialized only once. Thus it is OK to call this interface for an
+  // already initialized native bridge.
+  //
+  // Parameters:
+  //   runtime_cbs [IN] the pointer to NativeBridgeRuntimeCallbacks.
+  // Returns:
+  //   true iff initialization was successful.
+  bool (*initialize)(const NativeBridgeRuntimeCallbacks* runtime_cbs, const char* private_dir,
+                     const char* instruction_set);
+
+  // Load a shared library that is supported by the native bridge.
+  //
+  // Parameters:
+  //   libpath [IN] path to the shared library
+  //   flag [IN] the stardard RTLD_XXX defined in bionic dlfcn.h
+  // Returns:
+  //   The opaque handle of the shared library if sucessful, otherwise NULL
+  void* (*loadLibrary)(const char* libpath, int flag);
+
+  // Get a native bridge trampoline for specified native method. The trampoline has same
+  // sigature as the native method.
+  //
+  // Parameters:
+  //   handle [IN] the handle returned from loadLibrary
+  //   shorty [IN] short descriptor of native method
+  //   len [IN] length of shorty
+  // Returns:
+  //   address of trampoline if successful, otherwise NULL
+  void* (*getTrampoline)(void* handle, const char* name, const char* shorty, uint32_t len);
+
+  // Check whether native library is valid and is for an ABI that is supported by native bridge.
+  //
+  // Parameters:
+  //   libpath [IN] path to the shared library
+  // Returns:
+  //   TRUE if library is supported by native bridge, FALSE otherwise
+  bool (*isSupported)(const char* libpath);
+
+  // Provide environment values required by the app running with native bridge according to the
+  // instruction set.
+  //
+  // Parameters:
+  //    instruction_set [IN] the instruction set of the app
+  // Returns:
+  //    NULL if not supported by native bridge.
+  //    Otherwise, return all environment values to be set after fork.
+  const struct NativeBridgeRuntimeValues* (*getAppEnv)(const char* instruction_set);
+};
+
+// Runtime interfaces to native bridge.
+struct NativeBridgeRuntimeCallbacks {
+  // Get shorty of a Java method. The shorty is supposed to be persistent in memory.
+  //
+  // Parameters:
+  //   env [IN] pointer to JNIenv.
+  //   mid [IN] Java methodID.
+  // Returns:
+  //   short descriptor for method.
+  const char* (*getMethodShorty)(JNIEnv* env, jmethodID mid);
+
+  // Get number of native methods for specified class.
+  //
+  // Parameters:
+  //   env [IN] pointer to JNIenv.
+  //   clazz [IN] Java class object.
+  // Returns:
+  //   number of native methods.
+  uint32_t (*getNativeMethodCount)(JNIEnv* env, jclass clazz);
+
+  // Get at most 'method_count' native methods for specified class 'clazz'. Results are outputed
+  // via 'methods' [OUT]. The signature pointer in JNINativeMethod is reused as the method shorty.
+  //
+  // Parameters:
+  //   env [IN] pointer to JNIenv.
+  //   clazz [IN] Java class object.
+  //   methods [OUT] array of method with the name, shorty, and fnPtr.
+  //   method_count [IN] max number of elements in methods.
+  // Returns:
+  //   number of method it actually wrote to methods.
+  uint32_t (*getNativeMethods)(JNIEnv* env, jclass clazz, JNINativeMethod* methods,
+                               uint32_t method_count);
+};
+
+};  // namespace android
+
+#endif  // NATIVE_BRIDGE_H_
diff --git a/include/netutils/ifc.h b/include/netutils/ifc.h
index 1f5421d..3b27234 100644
--- a/include/netutils/ifc.h
+++ b/include/netutils/ifc.h
@@ -36,6 +36,7 @@
 
 #define RESET_IPV4_ADDRESSES 0x01
 #define RESET_IPV6_ADDRESSES 0x02
+#define RESET_IGNORE_INTERFACE_ADDRESS 0x04
 #define RESET_ALL_ADDRESSES  (RESET_IPV4_ADDRESSES | RESET_IPV6_ADDRESSES)
 extern int ifc_reset_connections(const char *ifname, const int reset_mask);
 
@@ -49,19 +50,8 @@
 extern int ifc_set_hwaddr(const char *name, const void *ptr);
 extern int ifc_clear_addresses(const char *name);
 
-/* This function is deprecated. Use ifc_add_route instead. */
-extern int ifc_add_host_route(const char *name, in_addr_t addr);
-extern int ifc_remove_host_routes(const char *name);
-extern int ifc_get_default_route(const char *ifname);
-/* This function is deprecated. Use ifc_add_route instead */
-extern int ifc_set_default_route(const char *ifname, in_addr_t gateway);
-/* This function is deprecated. Use ifc_add_route instead */
 extern int ifc_create_default_route(const char *name, in_addr_t addr);
 extern int ifc_remove_default_route(const char *ifname);
-extern int ifc_add_route(const char *name, const char *addr, int prefix_length,
-                         const char *gw);
-extern int ifc_remove_route(const char *ifname, const char *dst,
-                            int prefix_length, const char *gw);
 extern int ifc_get_info(const char *name, in_addr_t *addr, int *prefixLength,
                         unsigned *flags);
 
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index d8e938e..5d9c3ea 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -196,7 +196,7 @@
     { 00770, AID_SYSTEM, AID_CACHE,  0, "cache" },
     { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app" },
     { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app-private" },
-    { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/dalvik-cache" },
+    { 00771, AID_ROOT,   AID_ROOT,   0, "data/dalvik-cache" },
     { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/data" },
     { 00771, AID_SHELL,  AID_SHELL,  0, "data/local/tmp" },
     { 00771, AID_SHELL,  AID_SHELL,  0, "data/local" },
@@ -254,6 +254,8 @@
     /* the following files have enhanced capabilities and ARE included in user builds. */
     { 00750, AID_ROOT,      AID_SHELL,     (1 << CAP_SETUID) | (1 << CAP_SETGID), "system/bin/run-as" },
 
+    { 00750, AID_ROOT,      AID_ROOT,      0, "system/bin/uncrypt" },
+    { 00750, AID_ROOT,      AID_ROOT,      0, "system/bin/install-recovery.sh" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "system/bin/*" },
     { 00755, AID_ROOT,      AID_ROOT,      0, "system/lib/valgrind/*" },
     { 00755, AID_ROOT,      AID_ROOT,      0, "system/lib64/valgrind/*" },
@@ -263,7 +265,6 @@
     { 00750, AID_ROOT,      AID_SHELL,     0, "sbin/*" },
     { 00755, AID_ROOT,      AID_ROOT,      0, "bin/*" },
     { 00750, AID_ROOT,      AID_SHELL,     0, "init*" },
-    { 00750, AID_ROOT,      AID_SHELL,     0, "charger*" },
     { 00750, AID_ROOT,      AID_SHELL,     0, "sbin/fs_mgr" },
     { 00640, AID_ROOT,      AID_SHELL,     0, "fstab.*" },
     { 00644, AID_ROOT,      AID_ROOT,      0, 0 },
diff --git a/include/system/audio.h b/include/system/audio.h
index 8838e71..9a25cfb 100644
--- a/include/system/audio.h
+++ b/include/system/audio.h
@@ -20,6 +20,7 @@
 
 #include <stdbool.h>
 #include <stdint.h>
+#include <stdio.h>
 #include <sys/cdefs.h>
 #include <sys/types.h>
 
@@ -34,11 +35,17 @@
 /* device address used to refer to the standard remote submix */
 #define AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS "0"
 
+/* AudioFlinger and AudioPolicy services use I/O handles to identify audio sources and sinks */
 typedef int audio_io_handle_t;
+#define AUDIO_IO_HANDLE_NONE    0
 
 /* Audio stream types */
 typedef enum {
+    /* These values must kept in sync with
+     * frameworks/base/media/java/android/media/AudioSystem.java
+     */
     AUDIO_STREAM_DEFAULT          = -1,
+    AUDIO_STREAM_MIN              = 0,
     AUDIO_STREAM_VOICE_CALL       = 0,
     AUDIO_STREAM_SYSTEM           = 1,
     AUDIO_STREAM_RING             = 2,
@@ -46,7 +53,9 @@
     AUDIO_STREAM_ALARM            = 4,
     AUDIO_STREAM_NOTIFICATION     = 5,
     AUDIO_STREAM_BLUETOOTH_SCO    = 6,
-    AUDIO_STREAM_ENFORCED_AUDIBLE = 7, /* Sounds that cannot be muted by user and must be routed to speaker */
+    AUDIO_STREAM_ENFORCED_AUDIBLE = 7, /* Sounds that cannot be muted by user
+                                        * and must be routed to speaker
+                                        */
     AUDIO_STREAM_DTMF             = 8,
     AUDIO_STREAM_TTS              = 9,
 
@@ -55,7 +64,61 @@
 } audio_stream_type_t;
 
 /* Do not change these values without updating their counterparts
- * in media/java/android/media/MediaRecorder.java!
+ * in frameworks/base/media/java/android/media/AudioAttributes.java
+ */
+typedef enum {
+    AUDIO_CONTENT_TYPE_UNKNOWN      = 0,
+    AUDIO_CONTENT_TYPE_SPEECH       = 1,
+    AUDIO_CONTENT_TYPE_MUSIC        = 2,
+    AUDIO_CONTENT_TYPE_MOVIE        = 3,
+    AUDIO_CONTENT_TYPE_SONIFICATION = 4,
+
+    AUDIO_CONTENT_TYPE_CNT,
+    AUDIO_CONTENT_TYPE_MAX          = AUDIO_CONTENT_TYPE_CNT - 1,
+} audio_content_type_t;
+
+/* Do not change these values without updating their counterparts
+ * in frameworks/base/media/java/android/media/AudioAttributes.java
+ */
+typedef enum {
+    AUDIO_USAGE_UNKNOWN                            = 0,
+    AUDIO_USAGE_MEDIA                              = 1,
+    AUDIO_USAGE_VOICE_COMMUNICATION                = 2,
+    AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING     = 3,
+    AUDIO_USAGE_ALARM                              = 4,
+    AUDIO_USAGE_NOTIFICATION                       = 5,
+    AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE    = 6,
+    AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST = 7,
+    AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT = 8,
+    AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED = 9,
+    AUDIO_USAGE_NOTIFICATION_EVENT                 = 10,
+    AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY           = 11,
+    AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE     = 12,
+    AUDIO_USAGE_ASSISTANCE_SONIFICATION            = 13,
+    AUDIO_USAGE_GAME                               = 14,
+
+    AUDIO_USAGE_CNT,
+    AUDIO_USAGE_MAX                                = AUDIO_USAGE_CNT - 1,
+} audio_usage_t;
+
+typedef uint32_t audio_flags_mask_t;
+
+/* Do not change these values without updating their counterparts
+ * in frameworks/base/media/java/android/media/AudioAttributes.java
+ */
+enum {
+    AUDIO_FLAG_AUDIBILITY_ENFORCED = 0x1,
+    AUDIO_FLAG_SECURE              = 0x2,
+    AUDIO_FLAG_SCO                 = 0x4,
+    AUDIO_FLAG_BEACON              = 0x8,
+    AUDIO_FLAG_HW_AV_SYNC          = 0x10,
+    AUDIO_FLAG_HW_HOTWORD          = 0x20,
+};
+
+/* Do not change these values without updating their counterparts
+ * in frameworks/base/media/java/android/media/MediaRecorder.java,
+ * frameworks/av/services/audiopolicy/AudioPolicyService.cpp,
+ * and system/media/audio_effects/include/audio_effects/audio_effects_conf.h!
  */
 typedef enum {
     AUDIO_SOURCE_DEFAULT             = 0,
@@ -79,6 +142,16 @@
                                                 at the audio HAL. */
 } audio_source_t;
 
+/* Audio attributes */
+#define AUDIO_ATTRIBUTES_TAGS_MAX_SIZE 256
+typedef struct {
+    audio_content_type_t content_type;
+    audio_usage_t        usage;
+    audio_source_t       source;
+    audio_flags_mask_t   flags;
+    char                 tags[AUDIO_ATTRIBUTES_TAGS_MAX_SIZE]; /* UTF8 */
+} audio_attributes_t;
+
 /* special audio session values
  * (XXX: should this be living in the audio effects land?)
  */
@@ -93,18 +166,35 @@
      * (value must be 0)
      */
     AUDIO_SESSION_OUTPUT_MIX = 0,
+
+    /* application does not specify an explicit session ID to be used,
+     * and requests a new session ID to be allocated
+     * TODO use unique values for AUDIO_SESSION_OUTPUT_MIX and AUDIO_SESSION_ALLOCATE,
+     * after all uses have been updated from 0 to the appropriate symbol, and have been tested.
+     */
+    AUDIO_SESSION_ALLOCATE = 0,
 } audio_session_t;
 
+/* a unique ID allocated by AudioFlinger for use as a audio_io_handle_t or audio_session_t */
+typedef int audio_unique_id_t;
+
+#define AUDIO_UNIQUE_ID_ALLOCATE AUDIO_SESSION_ALLOCATE
+
 /* Audio sub formats (see enum audio_format). */
 
 /* PCM sub formats */
 typedef enum {
+    /* All of these are in native byte order */
     AUDIO_FORMAT_PCM_SUB_16_BIT          = 0x1, /* DO NOT CHANGE - PCM signed 16 bits */
     AUDIO_FORMAT_PCM_SUB_8_BIT           = 0x2, /* DO NOT CHANGE - PCM unsigned 8 bits */
     AUDIO_FORMAT_PCM_SUB_32_BIT          = 0x3, /* PCM signed .31 fixed point */
     AUDIO_FORMAT_PCM_SUB_8_24_BIT        = 0x4, /* PCM signed 7.24 fixed point */
+    AUDIO_FORMAT_PCM_SUB_FLOAT           = 0x5, /* PCM single-precision floating point */
+    AUDIO_FORMAT_PCM_SUB_24_BIT_PACKED   = 0x6, /* PCM signed .23 fixed point packed in 3 bytes */
 } audio_format_pcm_sub_fmt_t;
 
+/* The audio_format_*_sub_fmt_t declarations are not currently used */
+
 /* MP3 sub format field definition : can use 11 LSBs in the same way as MP3
  * frame header to specify bit rate, stereo mode, version...
  */
@@ -121,7 +211,16 @@
 
 /* AAC sub format field definition: specify profile or bitrate for recording... */
 typedef enum {
-    AUDIO_FORMAT_AAC_SUB_NONE            = 0x0,
+    AUDIO_FORMAT_AAC_SUB_MAIN            = 0x1,
+    AUDIO_FORMAT_AAC_SUB_LC              = 0x2,
+    AUDIO_FORMAT_AAC_SUB_SSR             = 0x4,
+    AUDIO_FORMAT_AAC_SUB_LTP             = 0x8,
+    AUDIO_FORMAT_AAC_SUB_HE_V1           = 0x10,
+    AUDIO_FORMAT_AAC_SUB_SCALABLE        = 0x20,
+    AUDIO_FORMAT_AAC_SUB_ERLC            = 0x40,
+    AUDIO_FORMAT_AAC_SUB_LD              = 0x80,
+    AUDIO_FORMAT_AAC_SUB_HE_V2           = 0x100,
+    AUDIO_FORMAT_AAC_SUB_ELD             = 0x200,
 } audio_format_aac_sub_fmt_t;
 
 /* VORBIS sub format field definition: specify quality for recording... */
@@ -129,7 +228,7 @@
     AUDIO_FORMAT_VORBIS_SUB_NONE         = 0x0,
 } audio_format_vorbis_sub_fmt_t;
 
-/* Audio format consists in a main format field (upper 8 bits) and a sub format
+/* Audio format consists of a main format field (upper 8 bits) and a sub format
  * field (lower 24 bits).
  *
  * The main format indicates the main codec type. The sub format field
@@ -146,24 +245,65 @@
     AUDIO_FORMAT_AMR_NB              = 0x02000000UL,
     AUDIO_FORMAT_AMR_WB              = 0x03000000UL,
     AUDIO_FORMAT_AAC                 = 0x04000000UL,
-    AUDIO_FORMAT_HE_AAC_V1           = 0x05000000UL,
-    AUDIO_FORMAT_HE_AAC_V2           = 0x06000000UL,
+    AUDIO_FORMAT_HE_AAC_V1           = 0x05000000UL, /* Deprecated, Use AUDIO_FORMAT_AAC_HE_V1*/
+    AUDIO_FORMAT_HE_AAC_V2           = 0x06000000UL, /* Deprecated, Use AUDIO_FORMAT_AAC_HE_V2*/
     AUDIO_FORMAT_VORBIS              = 0x07000000UL,
+    AUDIO_FORMAT_OPUS                = 0x08000000UL,
+    AUDIO_FORMAT_AC3                 = 0x09000000UL,
+    AUDIO_FORMAT_E_AC3               = 0x0A000000UL,
     AUDIO_FORMAT_MAIN_MASK           = 0xFF000000UL,
     AUDIO_FORMAT_SUB_MASK            = 0x00FFFFFFUL,
 
     /* Aliases */
+    /* note != AudioFormat.ENCODING_PCM_16BIT */
     AUDIO_FORMAT_PCM_16_BIT          = (AUDIO_FORMAT_PCM |
                                         AUDIO_FORMAT_PCM_SUB_16_BIT),
+    /* note != AudioFormat.ENCODING_PCM_8BIT */
     AUDIO_FORMAT_PCM_8_BIT           = (AUDIO_FORMAT_PCM |
                                         AUDIO_FORMAT_PCM_SUB_8_BIT),
     AUDIO_FORMAT_PCM_32_BIT          = (AUDIO_FORMAT_PCM |
                                         AUDIO_FORMAT_PCM_SUB_32_BIT),
     AUDIO_FORMAT_PCM_8_24_BIT        = (AUDIO_FORMAT_PCM |
                                         AUDIO_FORMAT_PCM_SUB_8_24_BIT),
+    AUDIO_FORMAT_PCM_FLOAT           = (AUDIO_FORMAT_PCM |
+                                        AUDIO_FORMAT_PCM_SUB_FLOAT),
+    AUDIO_FORMAT_PCM_24_BIT_PACKED   = (AUDIO_FORMAT_PCM |
+                                        AUDIO_FORMAT_PCM_SUB_24_BIT_PACKED),
+    AUDIO_FORMAT_AAC_MAIN            = (AUDIO_FORMAT_AAC |
+                                        AUDIO_FORMAT_AAC_SUB_MAIN),
+    AUDIO_FORMAT_AAC_LC              = (AUDIO_FORMAT_AAC |
+                                        AUDIO_FORMAT_AAC_SUB_LC),
+    AUDIO_FORMAT_AAC_SSR             = (AUDIO_FORMAT_AAC |
+                                        AUDIO_FORMAT_AAC_SUB_SSR),
+    AUDIO_FORMAT_AAC_LTP             = (AUDIO_FORMAT_AAC |
+                                        AUDIO_FORMAT_AAC_SUB_LTP),
+    AUDIO_FORMAT_AAC_HE_V1           = (AUDIO_FORMAT_AAC |
+                                        AUDIO_FORMAT_AAC_SUB_HE_V1),
+    AUDIO_FORMAT_AAC_SCALABLE        = (AUDIO_FORMAT_AAC |
+                                        AUDIO_FORMAT_AAC_SUB_SCALABLE),
+    AUDIO_FORMAT_AAC_ERLC            = (AUDIO_FORMAT_AAC |
+                                        AUDIO_FORMAT_AAC_SUB_ERLC),
+    AUDIO_FORMAT_AAC_LD              = (AUDIO_FORMAT_AAC |
+                                        AUDIO_FORMAT_AAC_SUB_LD),
+    AUDIO_FORMAT_AAC_HE_V2           = (AUDIO_FORMAT_AAC |
+                                        AUDIO_FORMAT_AAC_SUB_HE_V2),
+    AUDIO_FORMAT_AAC_ELD             = (AUDIO_FORMAT_AAC |
+                                        AUDIO_FORMAT_AAC_SUB_ELD),
 } audio_format_t;
 
+/* For the channel mask for position assignment representation */
 enum {
+
+/* These can be a complete audio_channel_mask_t. */
+
+    AUDIO_CHANNEL_NONE                      = 0x0,
+    AUDIO_CHANNEL_INVALID                   = 0xC0000000,
+
+/* These can be the bits portion of an audio_channel_mask_t
+ * with representation AUDIO_CHANNEL_REPRESENTATION_POSITION.
+ * Using these bits as a complete audio_channel_mask_t is deprecated.
+ */
+
     /* output channels */
     AUDIO_CHANNEL_OUT_FRONT_LEFT            = 0x1,
     AUDIO_CHANNEL_OUT_FRONT_RIGHT           = 0x2,
@@ -184,6 +324,8 @@
     AUDIO_CHANNEL_OUT_TOP_BACK_CENTER       = 0x10000,
     AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT        = 0x20000,
 
+/* TODO: should these be considered complete channel masks, or only bits? */
+
     AUDIO_CHANNEL_OUT_MONO     = AUDIO_CHANNEL_OUT_FRONT_LEFT,
     AUDIO_CHANNEL_OUT_STEREO   = (AUDIO_CHANNEL_OUT_FRONT_LEFT |
                                   AUDIO_CHANNEL_OUT_FRONT_RIGHT),
@@ -191,16 +333,26 @@
                                   AUDIO_CHANNEL_OUT_FRONT_RIGHT |
                                   AUDIO_CHANNEL_OUT_BACK_LEFT |
                                   AUDIO_CHANNEL_OUT_BACK_RIGHT),
-    AUDIO_CHANNEL_OUT_SURROUND = (AUDIO_CHANNEL_OUT_FRONT_LEFT |
+    AUDIO_CHANNEL_OUT_QUAD_BACK = AUDIO_CHANNEL_OUT_QUAD,
+    /* like AUDIO_CHANNEL_OUT_QUAD_BACK with *_SIDE_* instead of *_BACK_* */
+    AUDIO_CHANNEL_OUT_QUAD_SIDE = (AUDIO_CHANNEL_OUT_FRONT_LEFT |
                                   AUDIO_CHANNEL_OUT_FRONT_RIGHT |
-                                  AUDIO_CHANNEL_OUT_FRONT_CENTER |
-                                  AUDIO_CHANNEL_OUT_BACK_CENTER),
+                                  AUDIO_CHANNEL_OUT_SIDE_LEFT |
+                                  AUDIO_CHANNEL_OUT_SIDE_RIGHT),
     AUDIO_CHANNEL_OUT_5POINT1  = (AUDIO_CHANNEL_OUT_FRONT_LEFT |
                                   AUDIO_CHANNEL_OUT_FRONT_RIGHT |
                                   AUDIO_CHANNEL_OUT_FRONT_CENTER |
                                   AUDIO_CHANNEL_OUT_LOW_FREQUENCY |
                                   AUDIO_CHANNEL_OUT_BACK_LEFT |
                                   AUDIO_CHANNEL_OUT_BACK_RIGHT),
+    AUDIO_CHANNEL_OUT_5POINT1_BACK = AUDIO_CHANNEL_OUT_5POINT1,
+    /* like AUDIO_CHANNEL_OUT_5POINT1_BACK with *_SIDE_* instead of *_BACK_* */
+    AUDIO_CHANNEL_OUT_5POINT1_SIDE = (AUDIO_CHANNEL_OUT_FRONT_LEFT |
+                                  AUDIO_CHANNEL_OUT_FRONT_RIGHT |
+                                  AUDIO_CHANNEL_OUT_FRONT_CENTER |
+                                  AUDIO_CHANNEL_OUT_LOW_FREQUENCY |
+                                  AUDIO_CHANNEL_OUT_SIDE_LEFT |
+                                  AUDIO_CHANNEL_OUT_SIDE_RIGHT),
     // matches the correct AudioFormat.CHANNEL_OUT_7POINT1_SURROUND definition for 7.1
     AUDIO_CHANNEL_OUT_7POINT1  = (AUDIO_CHANNEL_OUT_FRONT_LEFT |
                                   AUDIO_CHANNEL_OUT_FRONT_RIGHT |
@@ -229,6 +381,8 @@
                                   AUDIO_CHANNEL_OUT_TOP_BACK_CENTER|
                                   AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT),
 
+/* These are bits only, not complete values */
+
     /* input channels */
     AUDIO_CHANNEL_IN_LEFT            = 0x4,
     AUDIO_CHANNEL_IN_RIGHT           = 0x8,
@@ -245,6 +399,8 @@
     AUDIO_CHANNEL_IN_VOICE_UPLINK    = 0x4000,
     AUDIO_CHANNEL_IN_VOICE_DNLINK    = 0x8000,
 
+/* TODO: should these be considered complete channel masks, or only bits, or deprecated? */
+
     AUDIO_CHANNEL_IN_MONO   = AUDIO_CHANNEL_IN_FRONT,
     AUDIO_CHANNEL_IN_STEREO = (AUDIO_CHANNEL_IN_LEFT | AUDIO_CHANNEL_IN_RIGHT),
     AUDIO_CHANNEL_IN_FRONT_BACK = (AUDIO_CHANNEL_IN_FRONT | AUDIO_CHANNEL_IN_BACK),
@@ -264,8 +420,111 @@
                                AUDIO_CHANNEL_IN_VOICE_DNLINK),
 };
 
+/* A channel mask per se only defines the presence or absence of a channel, not the order.
+ * But see AUDIO_INTERLEAVE_* below for the platform convention of order.
+ *
+ * audio_channel_mask_t is an opaque type and its internal layout should not
+ * be assumed as it may change in the future.
+ * Instead, always use the functions declared in this header to examine.
+ *
+ * These are the current representations:
+ *
+ *   AUDIO_CHANNEL_REPRESENTATION_POSITION
+ *     is a channel mask representation for position assignment.
+ *     Each low-order bit corresponds to the spatial position of a transducer (output),
+ *     or interpretation of channel (input).
+ *     The user of a channel mask needs to know the context of whether it is for output or input.
+ *     The constants AUDIO_CHANNEL_OUT_* or AUDIO_CHANNEL_IN_* apply to the bits portion.
+ *     It is not permitted for no bits to be set.
+ *
+ *   AUDIO_CHANNEL_REPRESENTATION_INDEX
+ *     is a channel mask representation for index assignment.
+ *     Each low-order bit corresponds to a selected channel.
+ *     There is no platform interpretation of the various bits.
+ *     There is no concept of output or input.
+ *     It is not permitted for no bits to be set.
+ *
+ * All other representations are reserved for future use.
+ *
+ * Warning: current representation distinguishes between input and output, but this will not the be
+ * case in future revisions of the platform. Wherever there is an ambiguity between input and output
+ * that is currently resolved by checking the channel mask, the implementer should look for ways to
+ * fix it with additional information outside of the mask.
+ */
 typedef uint32_t audio_channel_mask_t;
 
+/* Maximum number of channels for all representations */
+#define AUDIO_CHANNEL_COUNT_MAX             30
+
+/* log(2) of maximum number of representations, not part of public API */
+#define AUDIO_CHANNEL_REPRESENTATION_LOG2   2
+
+/* Representations */
+typedef enum {
+    AUDIO_CHANNEL_REPRESENTATION_POSITION    = 0,    // must be zero for compatibility
+    // 1 is reserved for future use
+    AUDIO_CHANNEL_REPRESENTATION_INDEX       = 2,
+    // 3 is reserved for future use
+} audio_channel_representation_t;
+
+/* The return value is undefined if the channel mask is invalid. */
+static inline uint32_t audio_channel_mask_get_bits(audio_channel_mask_t channel)
+{
+    return channel & ((1 << AUDIO_CHANNEL_COUNT_MAX) - 1);
+}
+
+/* The return value is undefined if the channel mask is invalid. */
+static inline audio_channel_representation_t audio_channel_mask_get_representation(
+        audio_channel_mask_t channel)
+{
+    // The right shift should be sufficient, but also "and" for safety in case mask is not 32 bits
+    return (audio_channel_representation_t)
+            ((channel >> AUDIO_CHANNEL_COUNT_MAX) & ((1 << AUDIO_CHANNEL_REPRESENTATION_LOG2) - 1));
+}
+
+/* Returns true if the channel mask is valid,
+ * or returns false for AUDIO_CHANNEL_NONE, AUDIO_CHANNEL_INVALID, and other invalid values.
+ * This function is unable to determine whether a channel mask for position assignment
+ * is invalid because an output mask has an invalid output bit set,
+ * or because an input mask has an invalid input bit set.
+ * All other APIs that take a channel mask assume that it is valid.
+ */
+static inline bool audio_channel_mask_is_valid(audio_channel_mask_t channel)
+{
+    uint32_t bits = audio_channel_mask_get_bits(channel);
+    audio_channel_representation_t representation = audio_channel_mask_get_representation(channel);
+    switch (representation) {
+    case AUDIO_CHANNEL_REPRESENTATION_POSITION:
+    case AUDIO_CHANNEL_REPRESENTATION_INDEX:
+        break;
+    default:
+        bits = 0;
+        break;
+    }
+    return bits != 0;
+}
+
+/* Not part of public API */
+static inline audio_channel_mask_t audio_channel_mask_from_representation_and_bits(
+        audio_channel_representation_t representation, uint32_t bits)
+{
+    return (audio_channel_mask_t) ((representation << AUDIO_CHANNEL_COUNT_MAX) | bits);
+}
+
+/* Expresses the convention when stereo audio samples are stored interleaved
+ * in an array.  This should improve readability by allowing code to use
+ * symbolic indices instead of hard-coded [0] and [1].
+ *
+ * For multi-channel beyond stereo, the platform convention is that channels
+ * are interleaved in order from least significant channel mask bit
+ * to most significant channel mask bit, with unused bits skipped.
+ * Any exceptions to this convention will be noted at the appropriate API.
+ */
+enum {
+    AUDIO_INTERLEAVE_LEFT   = 0,
+    AUDIO_INTERLEAVE_RIGHT  = 1,
+};
+
 typedef enum {
     AUDIO_MODE_INVALID          = -2,
     AUDIO_MODE_CURRENT          = -1,
@@ -278,7 +537,9 @@
     AUDIO_MODE_MAX              = AUDIO_MODE_CNT - 1,
 } audio_mode_t;
 
+/* This enum is deprecated */
 typedef enum {
+    AUDIO_IN_ACOUSTICS_NONE          = 0,
     AUDIO_IN_ACOUSTICS_AGC_ENABLE    = 0x0001,
     AUDIO_IN_ACOUSTICS_AGC_DISABLE   = 0,
     AUDIO_IN_ACOUSTICS_NS_ENABLE     = 0x0002,
@@ -304,11 +565,29 @@
     AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100,
     AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER    = 0x200,
     AUDIO_DEVICE_OUT_AUX_DIGITAL               = 0x400,
+    AUDIO_DEVICE_OUT_HDMI                      = AUDIO_DEVICE_OUT_AUX_DIGITAL,
+    /* uses an analog connection (multiplexed over the USB connector pins for instance) */
     AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET         = 0x800,
     AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET         = 0x1000,
+    /* USB accessory mode: your Android device is a USB device and the dock is a USB host */
     AUDIO_DEVICE_OUT_USB_ACCESSORY             = 0x2000,
+    /* USB host mode: your Android device is a USB host and the dock is a USB device */
     AUDIO_DEVICE_OUT_USB_DEVICE                = 0x4000,
     AUDIO_DEVICE_OUT_REMOTE_SUBMIX             = 0x8000,
+    /* Telephony voice TX path */
+    AUDIO_DEVICE_OUT_TELEPHONY_TX              = 0x10000,
+    /* Analog jack with line impedance detected */
+    AUDIO_DEVICE_OUT_LINE                      = 0x20000,
+    /* HDMI Audio Return Channel */
+    AUDIO_DEVICE_OUT_HDMI_ARC                  = 0x40000,
+    /* S/PDIF out */
+    AUDIO_DEVICE_OUT_SPDIF                     = 0x80000,
+    /* FM transmitter out */
+    AUDIO_DEVICE_OUT_FM                        = 0x100000,
+    /* Line out for av devices */
+    AUDIO_DEVICE_OUT_AUX_LINE                  = 0x200000,
+    /* limited-output speaker device for acoustic safety */
+    AUDIO_DEVICE_OUT_SPEAKER_SAFE              = 0x400000,
     AUDIO_DEVICE_OUT_DEFAULT                   = AUDIO_DEVICE_BIT_DEFAULT,
     AUDIO_DEVICE_OUT_ALL      = (AUDIO_DEVICE_OUT_EARPIECE |
                                  AUDIO_DEVICE_OUT_SPEAKER |
@@ -320,12 +599,19 @@
                                  AUDIO_DEVICE_OUT_BLUETOOTH_A2DP |
                                  AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
                                  AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER |
-                                 AUDIO_DEVICE_OUT_AUX_DIGITAL |
+                                 AUDIO_DEVICE_OUT_HDMI |
                                  AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET |
                                  AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET |
                                  AUDIO_DEVICE_OUT_USB_ACCESSORY |
                                  AUDIO_DEVICE_OUT_USB_DEVICE |
                                  AUDIO_DEVICE_OUT_REMOTE_SUBMIX |
+                                 AUDIO_DEVICE_OUT_TELEPHONY_TX |
+                                 AUDIO_DEVICE_OUT_LINE |
+                                 AUDIO_DEVICE_OUT_HDMI_ARC |
+                                 AUDIO_DEVICE_OUT_SPDIF |
+                                 AUDIO_DEVICE_OUT_FM |
+                                 AUDIO_DEVICE_OUT_AUX_LINE |
+                                 AUDIO_DEVICE_OUT_SPEAKER_SAFE |
                                  AUDIO_DEVICE_OUT_DEFAULT),
     AUDIO_DEVICE_OUT_ALL_A2DP = (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP |
                                  AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
@@ -343,13 +629,26 @@
     AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET = AUDIO_DEVICE_BIT_IN | 0x8,
     AUDIO_DEVICE_IN_WIRED_HEADSET         = AUDIO_DEVICE_BIT_IN | 0x10,
     AUDIO_DEVICE_IN_AUX_DIGITAL           = AUDIO_DEVICE_BIT_IN | 0x20,
+    AUDIO_DEVICE_IN_HDMI                  = AUDIO_DEVICE_IN_AUX_DIGITAL,
+    /* Telephony voice RX path */
     AUDIO_DEVICE_IN_VOICE_CALL            = AUDIO_DEVICE_BIT_IN | 0x40,
+    AUDIO_DEVICE_IN_TELEPHONY_RX          = AUDIO_DEVICE_IN_VOICE_CALL,
     AUDIO_DEVICE_IN_BACK_MIC              = AUDIO_DEVICE_BIT_IN | 0x80,
     AUDIO_DEVICE_IN_REMOTE_SUBMIX         = AUDIO_DEVICE_BIT_IN | 0x100,
     AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET     = AUDIO_DEVICE_BIT_IN | 0x200,
     AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET     = AUDIO_DEVICE_BIT_IN | 0x400,
     AUDIO_DEVICE_IN_USB_ACCESSORY         = AUDIO_DEVICE_BIT_IN | 0x800,
     AUDIO_DEVICE_IN_USB_DEVICE            = AUDIO_DEVICE_BIT_IN | 0x1000,
+    /* FM tuner input */
+    AUDIO_DEVICE_IN_FM_TUNER              = AUDIO_DEVICE_BIT_IN | 0x2000,
+    /* TV tuner input */
+    AUDIO_DEVICE_IN_TV_TUNER              = AUDIO_DEVICE_BIT_IN | 0x4000,
+    /* Analog jack with line impedance detected */
+    AUDIO_DEVICE_IN_LINE                  = AUDIO_DEVICE_BIT_IN | 0x8000,
+    /* S/PDIF in */
+    AUDIO_DEVICE_IN_SPDIF                 = AUDIO_DEVICE_BIT_IN | 0x10000,
+    AUDIO_DEVICE_IN_BLUETOOTH_A2DP        = AUDIO_DEVICE_BIT_IN | 0x20000,
+    AUDIO_DEVICE_IN_LOOPBACK              = AUDIO_DEVICE_BIT_IN | 0x40000,
     AUDIO_DEVICE_IN_DEFAULT               = AUDIO_DEVICE_BIT_IN | AUDIO_DEVICE_BIT_DEFAULT,
 
     AUDIO_DEVICE_IN_ALL     = (AUDIO_DEVICE_IN_COMMUNICATION |
@@ -357,16 +656,24 @@
                                AUDIO_DEVICE_IN_BUILTIN_MIC |
                                AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET |
                                AUDIO_DEVICE_IN_WIRED_HEADSET |
-                               AUDIO_DEVICE_IN_AUX_DIGITAL |
-                               AUDIO_DEVICE_IN_VOICE_CALL |
+                               AUDIO_DEVICE_IN_HDMI |
+                               AUDIO_DEVICE_IN_TELEPHONY_RX |
                                AUDIO_DEVICE_IN_BACK_MIC |
                                AUDIO_DEVICE_IN_REMOTE_SUBMIX |
                                AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET |
                                AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET |
                                AUDIO_DEVICE_IN_USB_ACCESSORY |
                                AUDIO_DEVICE_IN_USB_DEVICE |
+                               AUDIO_DEVICE_IN_FM_TUNER |
+                               AUDIO_DEVICE_IN_TV_TUNER |
+                               AUDIO_DEVICE_IN_LINE |
+                               AUDIO_DEVICE_IN_SPDIF |
+                               AUDIO_DEVICE_IN_BLUETOOTH_A2DP |
+                               AUDIO_DEVICE_IN_LOOPBACK |
                                AUDIO_DEVICE_IN_DEFAULT),
     AUDIO_DEVICE_IN_ALL_SCO = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET,
+    AUDIO_DEVICE_IN_ALL_USB  = (AUDIO_DEVICE_IN_USB_ACCESSORY |
+                                AUDIO_DEVICE_IN_USB_DEVICE),
 };
 
 typedef uint32_t audio_devices_t;
@@ -394,7 +701,8 @@
     AUDIO_OUTPUT_FLAG_DEEP_BUFFER = 0x8, // use deep audio buffers
     AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD = 0x10,  // offload playback of compressed
                                                 // streams to hardware codec
-    AUDIO_OUTPUT_FLAG_NON_BLOCKING = 0x20 // use non-blocking write
+    AUDIO_OUTPUT_FLAG_NON_BLOCKING = 0x20, // use non-blocking write
+    AUDIO_OUTPUT_FLAG_HW_AV_SYNC = 0x40 // output uses a hardware A/V synchronization source
 } audio_output_flags_t;
 
 /* The audio input flags are analogous to audio output flags.
@@ -403,8 +711,9 @@
  * attributes corresponding to the specified flags.
  */
 typedef enum {
-    AUDIO_INPUT_FLAG_NONE = 0x0,        // no attributes
-    AUDIO_INPUT_FLAG_FAST = 0x1,        // prefer an input that supports "fast tracks"
+    AUDIO_INPUT_FLAG_NONE       = 0x0,  // no attributes
+    AUDIO_INPUT_FLAG_FAST       = 0x1,  // prefer an input that supports "fast tracks"
+    AUDIO_INPUT_FLAG_HW_HOTWORD = 0x2,  // prefer an input that captures from hw hotword source
 } audio_input_flags_t;
 
 /* Additional information about compressed streams offloaded to
@@ -444,6 +753,264 @@
     is_streaming: false
 };
 
+/* common audio stream configuration parameters
+ * You should memset() the entire structure to zero before use to
+ * ensure forward compatibility
+ */
+struct audio_config {
+    uint32_t sample_rate;
+    audio_channel_mask_t channel_mask;
+    audio_format_t  format;
+    audio_offload_info_t offload_info;
+    size_t frame_count;
+};
+typedef struct audio_config audio_config_t;
+
+static const audio_config_t AUDIO_CONFIG_INITIALIZER = {
+    sample_rate: 0,
+    channel_mask: AUDIO_CHANNEL_NONE,
+    format: AUDIO_FORMAT_DEFAULT,
+    offload_info: {
+        version: AUDIO_OFFLOAD_INFO_VERSION_CURRENT,
+        size: sizeof(audio_offload_info_t),
+        sample_rate: 0,
+        channel_mask: 0,
+        format: AUDIO_FORMAT_DEFAULT,
+        stream_type: AUDIO_STREAM_VOICE_CALL,
+        bit_rate: 0,
+        duration_us: 0,
+        has_video: false,
+        is_streaming: false
+    },
+    frame_count: 0,
+};
+
+
+/* audio hw module handle functions or structures referencing a module */
+typedef int audio_module_handle_t;
+
+/******************************
+ *  Volume control
+ *****************************/
+
+/* If the audio hardware supports gain control on some audio paths,
+ * the platform can expose them in the audio_policy.conf file. The audio HAL
+ * will then implement gain control functions that will use the following data
+ * structures. */
+
+/* Type of gain control exposed by an audio port */
+#define AUDIO_GAIN_MODE_JOINT     0x1 /* supports joint channel gain control */
+#define AUDIO_GAIN_MODE_CHANNELS  0x2 /* supports separate channel gain control */
+#define AUDIO_GAIN_MODE_RAMP      0x4 /* supports gain ramps */
+
+typedef uint32_t audio_gain_mode_t;
+
+
+/* An audio_gain struct is a representation of a gain stage.
+ * A gain stage is always attached to an audio port. */
+struct audio_gain  {
+    audio_gain_mode_t    mode;          /* e.g. AUDIO_GAIN_MODE_JOINT */
+    audio_channel_mask_t channel_mask;  /* channels which gain an be controlled.
+                                           N/A if AUDIO_GAIN_MODE_CHANNELS is not supported */
+    int                  min_value;     /* minimum gain value in millibels */
+    int                  max_value;     /* maximum gain value in millibels */
+    int                  default_value; /* default gain value in millibels */
+    unsigned int         step_value;    /* gain step in millibels */
+    unsigned int         min_ramp_ms;   /* minimum ramp duration in ms */
+    unsigned int         max_ramp_ms;   /* maximum ramp duration in ms */
+};
+
+/* The gain configuration structure is used to get or set the gain values of a
+ * given port */
+struct audio_gain_config  {
+    int                  index;             /* index of the corresponding audio_gain in the
+                                               audio_port gains[] table */
+    audio_gain_mode_t    mode;              /* mode requested for this command */
+    audio_channel_mask_t channel_mask;      /* channels which gain value follows.
+                                               N/A in joint mode */
+    int                  values[sizeof(audio_channel_mask_t) * 8]; /* gain values in millibels
+                                               for each channel ordered from LSb to MSb in
+                                               channel mask. The number of values is 1 in joint
+                                               mode or popcount(channel_mask) */
+    unsigned int         ramp_duration_ms; /* ramp duration in ms */
+};
+
+/******************************
+ *  Routing control
+ *****************************/
+
+/* Types defined here are used to describe an audio source or sink at internal
+ * framework interfaces (audio policy, patch panel) or at the audio HAL.
+ * Sink and sources are grouped in a concept of “audio port” representing an
+ * audio end point at the edge of the system managed by the module exposing
+ * the interface. */
+
+/* Audio port role: either source or sink */
+typedef enum {
+    AUDIO_PORT_ROLE_NONE,
+    AUDIO_PORT_ROLE_SOURCE,
+    AUDIO_PORT_ROLE_SINK,
+} audio_port_role_t;
+
+/* Audio port type indicates if it is a session (e.g AudioTrack),
+ * a mix (e.g PlaybackThread output) or a physical device
+ * (e.g AUDIO_DEVICE_OUT_SPEAKER) */
+typedef enum {
+    AUDIO_PORT_TYPE_NONE,
+    AUDIO_PORT_TYPE_DEVICE,
+    AUDIO_PORT_TYPE_MIX,
+    AUDIO_PORT_TYPE_SESSION,
+} audio_port_type_t;
+
+/* Each port has a unique ID or handle allocated by policy manager */
+typedef int audio_port_handle_t;
+#define AUDIO_PORT_HANDLE_NONE 0
+
+
+/* maximum audio device address length */
+#define AUDIO_DEVICE_MAX_ADDRESS_LEN 32
+
+/* extension for audio port configuration structure when the audio port is a
+ * hardware device */
+struct audio_port_config_device_ext {
+    audio_module_handle_t hw_module;                /* module the device is attached to */
+    audio_devices_t       type;                     /* device type (e.g AUDIO_DEVICE_OUT_SPEAKER) */
+    char                  address[AUDIO_DEVICE_MAX_ADDRESS_LEN]; /* device address. "" if N/A */
+};
+
+/* extension for audio port configuration structure when the audio port is a
+ * sub mix */
+struct audio_port_config_mix_ext {
+    audio_module_handle_t hw_module;    /* module the stream is attached to */
+    audio_io_handle_t handle;           /* I/O handle of the input/output stream */
+    union {
+        //TODO: change use case for output streams: use strategy and mixer attributes
+        audio_stream_type_t stream;
+        audio_source_t      source;
+    } usecase;
+};
+
+/* extension for audio port configuration structure when the audio port is an
+ * audio session */
+struct audio_port_config_session_ext {
+    audio_session_t   session; /* audio session */
+};
+
+/* Flags indicating which fields are to be considered in struct audio_port_config */
+#define AUDIO_PORT_CONFIG_SAMPLE_RATE  0x1
+#define AUDIO_PORT_CONFIG_CHANNEL_MASK 0x2
+#define AUDIO_PORT_CONFIG_FORMAT       0x4
+#define AUDIO_PORT_CONFIG_GAIN         0x8
+#define AUDIO_PORT_CONFIG_ALL (AUDIO_PORT_CONFIG_SAMPLE_RATE | \
+                               AUDIO_PORT_CONFIG_CHANNEL_MASK | \
+                               AUDIO_PORT_CONFIG_FORMAT | \
+                               AUDIO_PORT_CONFIG_GAIN)
+
+/* audio port configuration structure used to specify a particular configuration of
+ * an audio port */
+struct audio_port_config {
+    audio_port_handle_t      id;           /* port unique ID */
+    audio_port_role_t        role;         /* sink or source */
+    audio_port_type_t        type;         /* device, mix ... */
+    unsigned int             config_mask;  /* e.g AUDIO_PORT_CONFIG_ALL */
+    unsigned int             sample_rate;  /* sampling rate in Hz */
+    audio_channel_mask_t     channel_mask; /* channel mask if applicable */
+    audio_format_t           format;       /* format if applicable */
+    struct audio_gain_config gain;         /* gain to apply if applicable */
+    union {
+        struct audio_port_config_device_ext  device;  /* device specific info */
+        struct audio_port_config_mix_ext     mix;     /* mix specific info */
+        struct audio_port_config_session_ext session; /* session specific info */
+    } ext;
+};
+
+
+/* max number of sampling rates in audio port */
+#define AUDIO_PORT_MAX_SAMPLING_RATES 16
+/* max number of channel masks in audio port */
+#define AUDIO_PORT_MAX_CHANNEL_MASKS 16
+/* max number of audio formats in audio port */
+#define AUDIO_PORT_MAX_FORMATS 16
+/* max number of gain controls in audio port */
+#define AUDIO_PORT_MAX_GAINS 16
+
+/* extension for audio port structure when the audio port is a hardware device */
+struct audio_port_device_ext {
+    audio_module_handle_t hw_module;    /* module the device is attached to */
+    audio_devices_t       type;         /* device type (e.g AUDIO_DEVICE_OUT_SPEAKER) */
+    char                  address[AUDIO_DEVICE_MAX_ADDRESS_LEN];
+};
+
+/* Latency class of the audio mix */
+typedef enum {
+    AUDIO_LATENCY_LOW,
+    AUDIO_LATENCY_NORMAL,
+} audio_mix_latency_class_t;
+
+/* extension for audio port structure when the audio port is a sub mix */
+struct audio_port_mix_ext {
+    audio_module_handle_t     hw_module;     /* module the stream is attached to */
+    audio_io_handle_t         handle;        /* I/O handle of the input.output stream */
+    audio_mix_latency_class_t latency_class; /* latency class */
+    // other attributes: routing strategies
+};
+
+/* extension for audio port structure when the audio port is an audio session */
+struct audio_port_session_ext {
+    audio_session_t   session; /* audio session */
+};
+
+
+struct audio_port {
+    audio_port_handle_t      id;                /* port unique ID */
+    audio_port_role_t        role;              /* sink or source */
+    audio_port_type_t        type;              /* device, mix ... */
+    unsigned int             num_sample_rates;  /* number of sampling rates in following array */
+    unsigned int             sample_rates[AUDIO_PORT_MAX_SAMPLING_RATES];
+    unsigned int             num_channel_masks; /* number of channel masks in following array */
+    audio_channel_mask_t     channel_masks[AUDIO_PORT_MAX_CHANNEL_MASKS];
+    unsigned int             num_formats;       /* number of formats in following array */
+    audio_format_t           formats[AUDIO_PORT_MAX_FORMATS];
+    unsigned int             num_gains;         /* number of gains in following array */
+    struct audio_gain        gains[AUDIO_PORT_MAX_GAINS];
+    struct audio_port_config active_config;     /* current audio port configuration */
+    union {
+        struct audio_port_device_ext  device;
+        struct audio_port_mix_ext     mix;
+        struct audio_port_session_ext session;
+    } ext;
+};
+
+/* An audio patch represents a connection between one or more source ports and
+ * one or more sink ports. Patches are connected and disconnected by audio policy manager or by
+ * applications via framework APIs.
+ * Each patch is identified by a handle at the interface used to create that patch. For instance,
+ * when a patch is created by the audio HAL, the HAL allocates and returns a handle.
+ * This handle is unique to a given audio HAL hardware module.
+ * But the same patch receives another system wide unique handle allocated by the framework.
+ * This unique handle is used for all transactions inside the framework.
+ */
+typedef int audio_patch_handle_t;
+#define AUDIO_PATCH_HANDLE_NONE 0
+
+#define AUDIO_PATCH_PORTS_MAX   16
+
+struct audio_patch {
+    audio_patch_handle_t id;            /* patch unique ID */
+    unsigned int      num_sources;      /* number of sources in following array */
+    struct audio_port_config sources[AUDIO_PATCH_PORTS_MAX];
+    unsigned int      num_sinks;        /* number of sinks in following array */
+    struct audio_port_config sinks[AUDIO_PATCH_PORTS_MAX];
+};
+
+
+
+/* a HW synchronization source returned by the audio HAL */
+typedef uint32_t audio_hw_sync_t;
+
+/* an invalid HW synchronization source indicating an error */
+#define AUDIO_HW_SYNC_INVALID 0
+
 static inline bool audio_is_output_device(audio_devices_t device)
 {
     if (((device & AUDIO_DEVICE_BIT_IN) == 0) &&
@@ -468,8 +1035,17 @@
     return (device & AUDIO_DEVICE_BIT_IN) == 0;
 }
 
+static inline bool audio_is_a2dp_in_device(audio_devices_t device)
+{
+    if ((device & AUDIO_DEVICE_BIT_IN) != 0) {
+        device &= ~AUDIO_DEVICE_BIT_IN;
+        if ((popcount(device) == 1) && (device & AUDIO_DEVICE_IN_BLUETOOTH_A2DP))
+            return true;
+    }
+    return false;
+}
 
-static inline bool audio_is_a2dp_device(audio_devices_t device)
+static inline bool audio_is_a2dp_out_device(audio_devices_t device)
 {
     if ((popcount(device) == 1) && (device & AUDIO_DEVICE_OUT_ALL_A2DP))
         return true;
@@ -477,6 +1053,12 @@
         return false;
 }
 
+// Deprecated - use audio_is_a2dp_out_device() instead
+static inline bool audio_is_a2dp_device(audio_devices_t device)
+{
+    return audio_is_a2dp_out_device(device);
+}
+
 static inline bool audio_is_bluetooth_sco_device(audio_devices_t device)
 {
     if ((device & AUDIO_DEVICE_BIT_IN) == 0) {
@@ -491,12 +1073,25 @@
     return false;
 }
 
+static inline bool audio_is_usb_out_device(audio_devices_t device)
+{
+    return ((popcount(device) == 1) && (device & AUDIO_DEVICE_OUT_ALL_USB));
+}
+
+static inline bool audio_is_usb_in_device(audio_devices_t device)
+{
+    if ((device & AUDIO_DEVICE_BIT_IN) != 0) {
+        device &= ~AUDIO_DEVICE_BIT_IN;
+        if (popcount(device) == 1 && (device & AUDIO_DEVICE_IN_ALL_USB) != 0)
+            return true;
+    }
+    return false;
+}
+
+/* OBSOLETE - use audio_is_usb_out_device() instead. */
 static inline bool audio_is_usb_device(audio_devices_t device)
 {
-    if ((popcount(device) == 1) && (device & AUDIO_DEVICE_OUT_ALL_USB))
-        return true;
-    else
-        return false;
+    return audio_is_usb_out_device(device);
 }
 
 static inline bool audio_is_remote_submix_device(audio_devices_t device)
@@ -508,75 +1103,200 @@
         return false;
 }
 
+/* Returns true if:
+ *  representation is valid, and
+ *  there is at least one channel bit set which _could_ correspond to an input channel, and
+ *  there are no channel bits set which could _not_ correspond to an input channel.
+ * Otherwise returns false.
+ */
 static inline bool audio_is_input_channel(audio_channel_mask_t channel)
 {
-    if ((channel & ~AUDIO_CHANNEL_IN_ALL) == 0)
-        return channel != 0;
-    else
+    uint32_t bits = audio_channel_mask_get_bits(channel);
+    switch (audio_channel_mask_get_representation(channel)) {
+    case AUDIO_CHANNEL_REPRESENTATION_POSITION:
+        if (bits & ~AUDIO_CHANNEL_IN_ALL) {
+            bits = 0;
+        }
+        // fall through
+    case AUDIO_CHANNEL_REPRESENTATION_INDEX:
+        return bits != 0;
+    default:
         return false;
+    }
 }
 
+/* Returns true if:
+ *  representation is valid, and
+ *  there is at least one channel bit set which _could_ correspond to an output channel, and
+ *  there are no channel bits set which could _not_ correspond to an output channel.
+ * Otherwise returns false.
+ */
 static inline bool audio_is_output_channel(audio_channel_mask_t channel)
 {
-    if ((channel & ~AUDIO_CHANNEL_OUT_ALL) == 0)
-        return channel != 0;
-    else
+    uint32_t bits = audio_channel_mask_get_bits(channel);
+    switch (audio_channel_mask_get_representation(channel)) {
+    case AUDIO_CHANNEL_REPRESENTATION_POSITION:
+        if (bits & ~AUDIO_CHANNEL_OUT_ALL) {
+            bits = 0;
+        }
+        // fall through
+    case AUDIO_CHANNEL_REPRESENTATION_INDEX:
+        return bits != 0;
+    default:
         return false;
+    }
 }
 
-/* Derive an output channel mask from a channel count.
+/* Returns the number of channels from an input channel mask,
+ * used in the context of audio input or recording.
+ * If a channel bit is set which could _not_ correspond to an input channel,
+ * it is excluded from the count.
+ * Returns zero if the representation is invalid.
+ */
+static inline uint32_t audio_channel_count_from_in_mask(audio_channel_mask_t channel)
+{
+    uint32_t bits = audio_channel_mask_get_bits(channel);
+    switch (audio_channel_mask_get_representation(channel)) {
+    case AUDIO_CHANNEL_REPRESENTATION_POSITION:
+        // TODO: We can now merge with from_out_mask and remove anding
+        bits &= AUDIO_CHANNEL_IN_ALL;
+        // fall through
+    case AUDIO_CHANNEL_REPRESENTATION_INDEX:
+        return popcount(bits);
+    default:
+        return 0;
+    }
+}
+
+/* Returns the number of channels from an output channel mask,
+ * used in the context of audio output or playback.
+ * If a channel bit is set which could _not_ correspond to an output channel,
+ * it is excluded from the count.
+ * Returns zero if the representation is invalid.
+ */
+static inline uint32_t audio_channel_count_from_out_mask(audio_channel_mask_t channel)
+{
+    uint32_t bits = audio_channel_mask_get_bits(channel);
+    switch (audio_channel_mask_get_representation(channel)) {
+    case AUDIO_CHANNEL_REPRESENTATION_POSITION:
+        // TODO: We can now merge with from_in_mask and remove anding
+        bits &= AUDIO_CHANNEL_OUT_ALL;
+        // fall through
+    case AUDIO_CHANNEL_REPRESENTATION_INDEX:
+        return popcount(bits);
+    default:
+        return 0;
+    }
+}
+
+/* Derive an output channel mask for position assignment from a channel count.
  * This is to be used when the content channel mask is unknown. The 1, 2, 4, 5, 6, 7 and 8 channel
  * cases are mapped to the standard game/home-theater layouts, but note that 4 is mapped to quad,
  * and not stereo + FC + mono surround. A channel count of 3 is arbitrarily mapped to stereo + FC
  * for continuity with stereo.
- * Returns the matching channel mask, or 0 if the number of channels exceeds that of the
- * configurations for which a default channel mask is defined.
+ * Returns the matching channel mask,
+ * or AUDIO_CHANNEL_NONE if the channel count is zero,
+ * or AUDIO_CHANNEL_INVALID if the channel count exceeds that of the
+ * configurations for which a default output channel mask is defined.
  */
 static inline audio_channel_mask_t audio_channel_out_mask_from_count(uint32_t channel_count)
 {
-    switch(channel_count) {
+    uint32_t bits;
+    switch (channel_count) {
+    case 0:
+        return AUDIO_CHANNEL_NONE;
     case 1:
-        return AUDIO_CHANNEL_OUT_MONO;
+        bits = AUDIO_CHANNEL_OUT_MONO;
+        break;
     case 2:
-        return AUDIO_CHANNEL_OUT_STEREO;
+        bits = AUDIO_CHANNEL_OUT_STEREO;
+        break;
     case 3:
-        return (AUDIO_CHANNEL_OUT_STEREO | AUDIO_CHANNEL_OUT_FRONT_CENTER);
+        bits = AUDIO_CHANNEL_OUT_STEREO | AUDIO_CHANNEL_OUT_FRONT_CENTER;
+        break;
     case 4: // 4.0
-        return AUDIO_CHANNEL_OUT_QUAD;
+        bits = AUDIO_CHANNEL_OUT_QUAD;
+        break;
     case 5: // 5.0
-        return (AUDIO_CHANNEL_OUT_QUAD | AUDIO_CHANNEL_OUT_FRONT_CENTER);
+        bits = AUDIO_CHANNEL_OUT_QUAD | AUDIO_CHANNEL_OUT_FRONT_CENTER;
+        break;
     case 6: // 5.1
-        return AUDIO_CHANNEL_OUT_5POINT1;
+        bits = AUDIO_CHANNEL_OUT_5POINT1;
+        break;
     case 7: // 6.1
-        return (AUDIO_CHANNEL_OUT_5POINT1 | AUDIO_CHANNEL_OUT_BACK_CENTER);
+        bits = AUDIO_CHANNEL_OUT_5POINT1 | AUDIO_CHANNEL_OUT_BACK_CENTER;
+        break;
     case 8:
-        return AUDIO_CHANNEL_OUT_7POINT1;
+        bits = AUDIO_CHANNEL_OUT_7POINT1;
+        break;
     default:
-        return 0;
+        return AUDIO_CHANNEL_INVALID;
     }
+    return audio_channel_mask_from_representation_and_bits(
+            AUDIO_CHANNEL_REPRESENTATION_POSITION, bits);
 }
 
-/* Similar to above, but for input.  Currently handles only mono and stereo. */
+/* Derive an input channel mask for position assignment from a channel count.
+ * Currently handles only mono and stereo.
+ * Returns the matching channel mask,
+ * or AUDIO_CHANNEL_NONE if the channel count is zero,
+ * or AUDIO_CHANNEL_INVALID if the channel count exceeds that of the
+ * configurations for which a default input channel mask is defined.
+ */
 static inline audio_channel_mask_t audio_channel_in_mask_from_count(uint32_t channel_count)
 {
+    uint32_t bits;
     switch (channel_count) {
+    case 0:
+        return AUDIO_CHANNEL_NONE;
     case 1:
-        return AUDIO_CHANNEL_IN_MONO;
+        bits = AUDIO_CHANNEL_IN_MONO;
+        break;
     case 2:
-        return AUDIO_CHANNEL_IN_STEREO;
+        bits = AUDIO_CHANNEL_IN_STEREO;
+        break;
     default:
-        return 0;
+        return AUDIO_CHANNEL_INVALID;
     }
+    return audio_channel_mask_from_representation_and_bits(
+            AUDIO_CHANNEL_REPRESENTATION_POSITION, bits);
+}
+
+/* Derive a channel mask for index assignment from a channel count.
+ * Returns the matching channel mask,
+ * or AUDIO_CHANNEL_NONE if the channel count is zero,
+ * or AUDIO_CHANNEL_INVALID if the channel count exceeds AUDIO_CHANNEL_COUNT_MAX.
+ */
+static inline audio_channel_mask_t audio_channel_mask_for_index_assignment_from_count(
+        uint32_t channel_count)
+{
+    if (channel_count == 0) {
+        return AUDIO_CHANNEL_NONE;
+    }
+    if (channel_count > AUDIO_CHANNEL_COUNT_MAX) {
+        return AUDIO_CHANNEL_INVALID;
+    }
+    uint32_t bits = (1 << channel_count) - 1;
+    return audio_channel_mask_from_representation_and_bits(
+            AUDIO_CHANNEL_REPRESENTATION_INDEX, bits);
 }
 
 static inline bool audio_is_valid_format(audio_format_t format)
 {
     switch (format & AUDIO_FORMAT_MAIN_MASK) {
     case AUDIO_FORMAT_PCM:
-        if (format != AUDIO_FORMAT_PCM_16_BIT &&
-                format != AUDIO_FORMAT_PCM_8_BIT) {
+        switch (format) {
+        case AUDIO_FORMAT_PCM_16_BIT:
+        case AUDIO_FORMAT_PCM_8_BIT:
+        case AUDIO_FORMAT_PCM_32_BIT:
+        case AUDIO_FORMAT_PCM_8_24_BIT:
+        case AUDIO_FORMAT_PCM_FLOAT:
+        case AUDIO_FORMAT_PCM_24_BIT_PACKED:
+            return true;
+        default:
             return false;
         }
+        /* not reached */
     case AUDIO_FORMAT_MP3:
     case AUDIO_FORMAT_AMR_NB:
     case AUDIO_FORMAT_AMR_WB:
@@ -584,6 +1304,9 @@
     case AUDIO_FORMAT_HE_AAC_V1:
     case AUDIO_FORMAT_HE_AAC_V2:
     case AUDIO_FORMAT_VORBIS:
+    case AUDIO_FORMAT_OPUS:
+    case AUDIO_FORMAT_AC3:
+    case AUDIO_FORMAT_E_AC3:
         return true;
     default:
         return false;
@@ -604,18 +1327,41 @@
     case AUDIO_FORMAT_PCM_8_24_BIT:
         size = sizeof(int32_t);
         break;
+    case AUDIO_FORMAT_PCM_24_BIT_PACKED:
+        size = sizeof(uint8_t) * 3;
+        break;
     case AUDIO_FORMAT_PCM_16_BIT:
         size = sizeof(int16_t);
         break;
     case AUDIO_FORMAT_PCM_8_BIT:
         size = sizeof(uint8_t);
         break;
+    case AUDIO_FORMAT_PCM_FLOAT:
+        size = sizeof(float);
+        break;
     default:
         break;
     }
     return size;
 }
 
+/* converts device address to string sent to audio HAL via set_parameters */
+static char *audio_device_address_to_parameter(audio_devices_t device, const char *address)
+{
+    const size_t kSize = AUDIO_DEVICE_MAX_ADDRESS_LEN + sizeof("a2dp_sink_address=");
+    char param[kSize];
+
+    if (device & AUDIO_DEVICE_OUT_ALL_A2DP)
+        snprintf(param, kSize, "%s=%s", "a2dp_sink_address", address);
+    else if (device & AUDIO_DEVICE_OUT_REMOTE_SUBMIX)
+        snprintf(param, kSize, "%s=%s", "mix", address);
+    else
+        snprintf(param, kSize, "%s", address);
+
+    return strdup(param);
+}
+
+
 __END_DECLS
 
 #endif  // ANDROID_AUDIO_CORE_H
diff --git a/include/system/audio_policy.h b/include/system/audio_policy.h
index a6554de..2881104 100644
--- a/include/system/audio_policy.h
+++ b/include/system/audio_policy.h
@@ -44,6 +44,7 @@
     AUDIO_POLICY_FORCE_DIGITAL_DOCK,
     AUDIO_POLICY_FORCE_NO_BT_A2DP, /* A2DP sink is not preferred to speaker or wired HS */
     AUDIO_POLICY_FORCE_SYSTEM_ENFORCED,
+    AUDIO_POLICY_FORCE_HDMI_SYSTEM_AUDIO_ENFORCED,
 
     AUDIO_POLICY_FORCE_CFG_CNT,
     AUDIO_POLICY_FORCE_CFG_MAX = AUDIO_POLICY_FORCE_CFG_CNT - 1,
@@ -58,6 +59,7 @@
     AUDIO_POLICY_FORCE_FOR_RECORD,
     AUDIO_POLICY_FORCE_FOR_DOCK,
     AUDIO_POLICY_FORCE_FOR_SYSTEM,
+    AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO,
 
     AUDIO_POLICY_FORCE_USE_CNT,
     AUDIO_POLICY_FORCE_USE_MAX = AUDIO_POLICY_FORCE_USE_CNT - 1,
diff --git a/include/system/graphics.h b/include/system/graphics.h
index be86ae4..c3fca97 100644
--- a/include/system/graphics.h
+++ b/include/system/graphics.h
@@ -165,24 +165,104 @@
     /*
      * Android RAW sensor format:
      *
-     * This format is exposed outside of the HAL to applications.
+     * This format is exposed outside of the camera HAL to applications.
      *
-     * RAW_SENSOR is a single-channel 16-bit format, typically representing raw
-     * Bayer-pattern images from an image sensor, with minimal processing.
+     * RAW_SENSOR is a single-channel, 16-bit, little endian  format, typically
+     * representing raw Bayer-pattern images from an image sensor, with minimal
+     * processing.
      *
      * The exact pixel layout of the data in the buffer is sensor-dependent, and
      * needs to be queried from the camera device.
      *
      * Generally, not all 16 bits are used; more common values are 10 or 12
-     * bits. All parameters to interpret the raw data (black and white points,
+     * bits. If not all bits are used, the lower-order bits are filled first.
+     * All parameters to interpret the raw data (black and white points,
      * color space, etc) must be queried from the camera device.
      *
      * This format assumes
      * - an even width
      * - an even height
-     * - a horizontal stride multiple of 16 pixels (32 bytes).
+     * - a horizontal stride multiple of 16 pixels
+     * - a vertical stride equal to the height
+     * - strides are specified in pixels, not in bytes
+     *
+     *   size = stride * height * 2
+     *
+     * This format must be accepted by the gralloc module when used with the
+     * following usage flags:
+     *    - GRALLOC_USAGE_HW_CAMERA_*
+     *    - GRALLOC_USAGE_SW_*
+     *    - GRALLOC_USAGE_RENDERSCRIPT
      */
-    HAL_PIXEL_FORMAT_RAW_SENSOR = 0x20,
+    HAL_PIXEL_FORMAT_RAW16 = 0x20,
+    HAL_PIXEL_FORMAT_RAW_SENSOR = 0x20, // TODO(rubenbrunk): Remove RAW_SENSOR.
+
+    /*
+     * Android RAW10 format:
+     *
+     * This format is exposed outside of the camera HAL to applications.
+     *
+     * RAW10 is a single-channel, 10-bit per pixel, densely packed in each row,
+     * unprocessed format, usually representing raw Bayer-pattern images coming from
+     * an image sensor.
+     *
+     * In an image buffer with this format, starting from the first pixel of each
+     * row, each 4 consecutive pixels are packed into 5 bytes (40 bits). Each one
+     * of the first 4 bytes contains the top 8 bits of each pixel, The fifth byte
+     * contains the 2 least significant bits of the 4 pixels, the exact layout data
+     * for each 4 consecutive pixels is illustrated below (Pi[j] stands for the jth
+     * bit of the ith pixel):
+     *
+     *          bit 7                                     bit 0
+     *          =====|=====|=====|=====|=====|=====|=====|=====|
+     * Byte 0: |P0[9]|P0[8]|P0[7]|P0[6]|P0[5]|P0[4]|P0[3]|P0[2]|
+     *         |-----|-----|-----|-----|-----|-----|-----|-----|
+     * Byte 1: |P1[9]|P1[8]|P1[7]|P1[6]|P1[5]|P1[4]|P1[3]|P1[2]|
+     *         |-----|-----|-----|-----|-----|-----|-----|-----|
+     * Byte 2: |P2[9]|P2[8]|P2[7]|P2[6]|P2[5]|P2[4]|P2[3]|P2[2]|
+     *         |-----|-----|-----|-----|-----|-----|-----|-----|
+     * Byte 3: |P3[9]|P3[8]|P3[7]|P3[6]|P3[5]|P3[4]|P3[3]|P3[2]|
+     *         |-----|-----|-----|-----|-----|-----|-----|-----|
+     * Byte 4: |P3[1]|P3[0]|P2[1]|P2[0]|P1[1]|P1[0]|P0[1]|P0[0]|
+     *          ===============================================
+     *
+     * This format assumes
+     * - a width multiple of 4 pixels
+     * - an even height
+     * - a vertical stride equal to the height
+     * - strides are specified in bytes, not in pixels
+     *
+     *   size = stride * height
+     *
+     * When stride is equal to width * (10 / 8), there will be no padding bytes at
+     * the end of each row, the entire image data is densely packed. When stride is
+     * larger than width * (10 / 8), padding bytes will be present at the end of each
+     * row (including the last row).
+     *
+     * This format must be accepted by the gralloc module when used with the
+     * following usage flags:
+     *    - GRALLOC_USAGE_HW_CAMERA_*
+     *    - GRALLOC_USAGE_SW_*
+     *    - GRALLOC_USAGE_RENDERSCRIPT
+     */
+    HAL_PIXEL_FORMAT_RAW10 = 0x25,
+
+    /*
+     * Android opaque RAW format:
+     *
+     * This format is exposed outside of the camera HAL to applications.
+     *
+     * RAW_OPAQUE is a format for unprocessed raw image buffers coming from an
+     * image sensor. The actual structure of buffers of this format is
+     * implementation-dependent.
+     *
+     * This format must be accepted by the gralloc module when used with the
+     * following usage flags:
+     *    - GRALLOC_USAGE_HW_CAMERA_*
+     *    - GRALLOC_USAGE_SW_*
+     *    - GRALLOC_USAGE_RENDERSCRIPT
+     */
+    HAL_PIXEL_FORMAT_RAW_OPAQUE = 0x24,
 
     /*
      * Android binary blob graphics buffer format:
@@ -297,6 +377,136 @@
     HAL_TRANSFORM_RESERVED  = 0x08,
 };
 
+/**
+ * Colorspace Definitions
+ * ======================
+ *
+ * Colorspace is the definition of how pixel values should be interpreted.
+ * It includes primaries (including white point) and the transfer
+ * characteristic function, which describes both gamma curve and numeric
+ * range (within the bit depth).
+ */
+
+enum {
+    /*
+     * Arbitrary colorspace with manually defined characteristics.
+     * Colorspace definition must be communicated separately.
+     *
+     * This is used when specifying primaries, transfer characteristics,
+     * etc. separately.
+     *
+     * A typical use case is in video encoding parameters (e.g. for H.264),
+     * where a colorspace can have separately defined primaries, transfer
+     * characteristics, etc.
+     */
+    HAL_COLORSPACE_ARBITRARY = 0x1,
+
+    /*
+     * YCbCr Colorspaces
+     * -----------------
+     *
+     * Primaries are given using (x,y) coordinates in the CIE 1931 definition
+     * of x and y specified by ISO 11664-1.
+     *
+     * Transfer characteristics are the opto-electronic transfer characteristic
+     * at the source as a function of linear optical intensity (luminance).
+     */
+
+    /*
+     * JPEG File Interchange Format (JFIF)
+     *
+     * Same model as BT.601-625, but all values (Y, Cb, Cr) range from 0 to 255
+     *
+     * Transfer characteristic curve:
+     *  E = 1.099 * L ^ 0.45 - 0.099, 1.00 >= L >= 0.018
+     *  E = 4.500 L, 0.018 > L >= 0
+     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
+     *      E - corresponding electrical signal
+     *
+     * Primaries:       x       y
+     *  green           0.290   0.600
+     *  blue            0.150   0.060
+     *  red             0.640   0.330
+     *  white (D65)     0.3127  0.3290
+     */
+    HAL_COLORSPACE_JFIF = 0x101,
+
+    /*
+     * ITU-R Recommendation 601 (BT.601) - 625-line
+     *
+     * Standard-definition television, 625 Lines (PAL)
+     *
+     * For 8-bit-depth formats:
+     * Luma (Y) samples should range from 16 to 235, inclusive
+     * Chroma (Cb, Cr) samples should range from 16 to 240, inclusive
+     *
+     * For 10-bit-depth formats:
+     * Luma (Y) samples should range from 64 to 940, inclusive
+     * Chroma (Cb, Cr) samples should range from 64 to 960, inclusive
+     *
+     * Transfer characteristic curve:
+     *  E = 1.099 * L ^ 0.45 - 0.099, 1.00 >= L >= 0.018
+     *  E = 4.500 L, 0.018 > L >= 0
+     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
+     *      E - corresponding electrical signal
+     *
+     * Primaries:       x       y
+     *  green           0.290   0.600
+     *  blue            0.150   0.060
+     *  red             0.640   0.330
+     *  white (D65)     0.3127  0.3290
+     */
+    HAL_COLORSPACE_BT601_625 = 0x102,
+
+    /*
+     * ITU-R Recommendation 601 (BT.601) - 525-line
+     *
+     * Standard-definition television, 525 Lines (NTSC)
+     *
+     * For 8-bit-depth formats:
+     * Luma (Y) samples should range from 16 to 235, inclusive
+     * Chroma (Cb, Cr) samples should range from 16 to 240, inclusive
+     *
+     * For 10-bit-depth formats:
+     * Luma (Y) samples should range from 64 to 940, inclusive
+     * Chroma (Cb, Cr) samples should range from 64 to 960, inclusive
+     *
+     * Transfer characteristic curve:
+     *  E = 1.099 * L ^ 0.45 - 0.099, 1.00 >= L >= 0.018
+     *  E = 4.500 L, 0.018 > L >= 0
+     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
+     *      E - corresponding electrical signal
+     *
+     * Primaries:       x       y
+     *  green           0.310   0.595
+     *  blue            0.155   0.070
+     *  red             0.630   0.340
+     *  white (D65)     0.3127  0.3290
+     */
+    HAL_COLORSPACE_BT601_525 = 0x103,
+
+    /*
+     * ITU-R Recommendation 709 (BT.709)
+     *
+     * High-definition television
+     *
+     * For 8-bit-depth formats:
+     * Luma (Y) samples should range from 16 to 235, inclusive
+     * Chroma (Cb, Cr) samples should range from 16 to 240, inclusive
+     *
+     * For 10-bit-depth formats:
+     * Luma (Y) samples should range from 64 to 940, inclusive
+     * Chroma (Cb, Cr) samples should range from 64 to 960, inclusive
+     *
+     * Primaries:       x       y
+     *  green           0.300   0.600
+     *  blue            0.150   0.060
+     *  red             0.640   0.330
+     *  white (D65)     0.3127  0.3290
+     */
+    HAL_COLORSPACE_BT709 = 0x104,
+};
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/system/sound_trigger.h b/include/system/sound_trigger.h
new file mode 100644
index 0000000..773e4f7
--- /dev/null
+++ b/include/system/sound_trigger.h
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2014 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 ANDROID_SOUND_TRIGGER_H
+#define ANDROID_SOUND_TRIGGER_H
+
+#include <stdbool.h>
+#include <system/audio.h>
+
+#define SOUND_TRIGGER_MAX_STRING_LEN 64 /* max length of strings in properties or
+                                           descriptor structs */
+#define SOUND_TRIGGER_MAX_LOCALE_LEN 6  /* max length of locale string. e.g en_US */
+#define SOUND_TRIGGER_MAX_USERS 10      /* max number of concurrent users */
+#define SOUND_TRIGGER_MAX_PHRASES 10    /* max number of concurrent phrases */
+
+typedef enum {
+    SOUND_TRIGGER_STATE_NO_INIT = -1,   /* The sound trigger service is not initialized */
+    SOUND_TRIGGER_STATE_ENABLED = 0,    /* The sound trigger service is enabled */
+    SOUND_TRIGGER_STATE_DISABLED = 1    /* The sound trigger service is disabled */
+} sound_trigger_service_state_t;
+
+#define RECOGNITION_MODE_VOICE_TRIGGER 0x1       /* simple voice trigger */
+#define RECOGNITION_MODE_USER_IDENTIFICATION 0x2 /* trigger only if one user in model identified */
+#define RECOGNITION_MODE_USER_AUTHENTICATION 0x4 /* trigger only if one user in mode
+                                                    authenticated */
+#define RECOGNITION_STATUS_SUCCESS 0
+#define RECOGNITION_STATUS_ABORT 1
+#define RECOGNITION_STATUS_FAILURE 2
+
+#define SOUND_MODEL_STATUS_UPDATED 0
+
+typedef enum {
+    SOUND_MODEL_TYPE_UNKNOWN = -1,    /* use for unspecified sound model type */
+    SOUND_MODEL_TYPE_KEYPHRASE = 0    /* use for key phrase sound models */
+} sound_trigger_sound_model_type_t;
+
+typedef struct sound_trigger_uuid_s {
+    unsigned int   timeLow;
+    unsigned short timeMid;
+    unsigned short timeHiAndVersion;
+    unsigned short clockSeq;
+    unsigned char  node[6];
+} sound_trigger_uuid_t;
+
+/*
+ * sound trigger implementation descriptor read by the framework via get_properties().
+ * Used by SoundTrigger service to report to applications and manage concurrency and policy.
+ */
+struct sound_trigger_properties {
+    char                 implementor[SOUND_TRIGGER_MAX_STRING_LEN]; /* implementor name */
+    char                 description[SOUND_TRIGGER_MAX_STRING_LEN]; /* implementation description */
+    unsigned int         version;               /* implementation version */
+    sound_trigger_uuid_t uuid;                  /* unique implementation ID.
+                                                   Must change with version each version */
+    unsigned int         max_sound_models;      /* maximum number of concurrent sound models
+                                                   loaded */
+    unsigned int         max_key_phrases;       /* maximum number of key phrases */
+    unsigned int         max_users;             /* maximum number of concurrent users detected */
+    unsigned int         recognition_modes;     /* all supported modes.
+                                                   e.g RECOGNITION_MODE_VOICE_TRIGGER */
+    bool                 capture_transition;    /* supports seamless transition from detection
+                                                   to capture */
+    unsigned int         max_buffer_ms;         /* maximum buffering capacity in ms if
+                                                   capture_transition is true*/
+    bool                 concurrent_capture;    /* supports capture by other use cases while
+                                                   detection is active */
+    bool                 trigger_in_event;      /* returns the trigger capture in event */
+    unsigned int         power_consumption_mw;  /* Rated power consumption when detection is active
+                                                   with TDB silence/sound/speech ratio */
+};
+
+typedef int sound_trigger_module_handle_t;
+
+struct sound_trigger_module_descriptor {
+    sound_trigger_module_handle_t   handle;
+    struct sound_trigger_properties properties;
+};
+
+typedef int sound_model_handle_t;
+
+/*
+ * Generic sound model descriptor. This struct is the header of a larger block passed to
+ * load_sound_model() and containing the binary data of the sound model.
+ * Proprietary representation of users in binary data must match information indicated
+ * by users field
+ */
+struct sound_trigger_sound_model {
+    sound_trigger_sound_model_type_t type;        /* model type. e.g. SOUND_MODEL_TYPE_KEYPHRASE */
+    sound_trigger_uuid_t             uuid;        /* unique sound model ID. */
+    sound_trigger_uuid_t             vendor_uuid; /* unique vendor ID. Identifies the engine the
+                                                  sound model was build for */
+    unsigned int                     data_size;   /* size of opaque model data */
+    unsigned int                     data_offset; /* offset of opaque data start from head of struct
+                                                    (e.g sizeof struct sound_trigger_sound_model) */
+};
+
+/* key phrase descriptor */
+struct sound_trigger_phrase {
+    unsigned int id;                /* keyphrase ID */
+    unsigned int recognition_mode;  /* recognition modes supported by this key phrase */
+    unsigned int num_users;         /* number of users in the key phrase */
+    unsigned int users[SOUND_TRIGGER_MAX_USERS]; /* users ids: (not uid_t but sound trigger
+                                                 specific IDs */
+    char         locale[SOUND_TRIGGER_MAX_LOCALE_LEN]; /* locale - JAVA Locale style (e.g. en_US) */
+    char         text[SOUND_TRIGGER_MAX_STRING_LEN];   /* phrase text in UTF-8 format. */
+};
+
+/*
+ * Specialized sound model for key phrase detection.
+ * Proprietary representation of key phrases in binary data must match information indicated
+ * by phrases field
+ */
+struct sound_trigger_phrase_sound_model {
+    struct sound_trigger_sound_model common;
+    unsigned int                     num_phrases;   /* number of key phrases in model */
+    struct sound_trigger_phrase      phrases[SOUND_TRIGGER_MAX_PHRASES];
+};
+
+
+/*
+ * Generic recognition event sent via recognition callback
+ */
+struct sound_trigger_recognition_event {
+    int                              status;            /* recognition status e.g.
+                                                           RECOGNITION_STATUS_SUCCESS */
+    sound_trigger_sound_model_type_t type;              /* event type, same as sound model type.
+                                                           e.g. SOUND_MODEL_TYPE_KEYPHRASE */
+    sound_model_handle_t             model;             /* loaded sound model that triggered the
+                                                           event */
+    bool                             capture_available; /* it is possible to capture audio from this
+                                                           utterance buffered by the
+                                                           implementation */
+    int                              capture_session;   /* audio session ID. framework use */
+    int                              capture_delay_ms;  /* delay in ms between end of model
+                                                           detection and start of audio available
+                                                           for capture. A negative value is possible
+                                                           (e.g. if key phrase is also available for
+                                                           capture */
+    int                              capture_preamble_ms; /* duration in ms of audio captured
+                                                            before the start of the trigger.
+                                                            0 if none. */
+    bool                             trigger_in_data; /* the opaque data is the capture of
+                                                            the trigger sound */
+    audio_config_t                   audio_config;        /* audio format of either the trigger in
+                                                             event data or to use for capture of the
+                                                             rest of the utterance */
+    unsigned int                     data_size;         /* size of opaque event data */
+    unsigned int                     data_offset;       /* offset of opaque data start from start of
+                                                          this struct (e.g sizeof struct
+                                                          sound_trigger_phrase_recognition_event) */
+};
+
+/*
+ * Confidence level for each user in struct sound_trigger_phrase_recognition_extra
+ */
+struct sound_trigger_confidence_level {
+    unsigned int user_id;   /* user ID */
+    unsigned int level;     /* confidence level in percent (0 - 100).
+                               - min level for recognition configuration
+                               - detected level for recognition event */
+};
+
+/*
+ * Specialized recognition event for key phrase detection
+ */
+struct sound_trigger_phrase_recognition_extra {
+    unsigned int id;                /* keyphrase ID */
+    unsigned int recognition_modes; /* recognition modes used for this keyphrase */
+    unsigned int confidence_level;  /* confidence level for mode RECOGNITION_MODE_VOICE_TRIGGER */
+    unsigned int num_levels;        /* number of user confidence levels */
+    struct sound_trigger_confidence_level levels[SOUND_TRIGGER_MAX_USERS];
+};
+
+struct sound_trigger_phrase_recognition_event {
+    struct sound_trigger_recognition_event common;
+    unsigned int                           num_phrases;
+    struct sound_trigger_phrase_recognition_extra phrase_extras[SOUND_TRIGGER_MAX_PHRASES];
+};
+
+/*
+ * configuration for sound trigger capture session passed to start_recognition()
+ */
+struct sound_trigger_recognition_config {
+    audio_io_handle_t    capture_handle;    /* IO handle that will be used for capture.
+                                            N/A if capture_requested is false */
+    audio_devices_t      capture_device;    /* input device requested for detection capture */
+    bool                 capture_requested; /* capture and buffer audio for this recognition
+                                            instance */
+    unsigned int         num_phrases;   /* number of key phrases recognition extras */
+    struct sound_trigger_phrase_recognition_extra phrases[SOUND_TRIGGER_MAX_PHRASES];
+                                           /* configuration for each key phrase */
+    unsigned int        data_size;         /* size of opaque capture configuration data */
+    unsigned int        data_offset;       /* offset of opaque data start from start of this struct
+                                           (e.g sizeof struct sound_trigger_recognition_config) */
+};
+
+/*
+ * Event sent via load sound model callback
+ */
+struct sound_trigger_model_event {
+    int                  status;      /* sound model status e.g. SOUND_MODEL_STATUS_UPDATED */
+    sound_model_handle_t model;       /* loaded sound model that triggered the event */
+    unsigned int         data_size;   /* size of event data if any. Size of updated sound model if
+                                       status is SOUND_MODEL_STATUS_UPDATED */
+    unsigned int         data_offset; /* offset of data start from start of this struct
+                                       (e.g sizeof struct sound_trigger_model_event) */
+};
+
+
+#endif  // ANDROID_SOUND_TRIGGER_H
diff --git a/include/system/window.h b/include/system/window.h
index 31f202f..bf93b79 100644
--- a/include/system/window.h
+++ b/include/system/window.h
@@ -242,7 +242,26 @@
      * The consumer gralloc usage bits currently set by the consumer.
      * The values are defined in hardware/libhardware/include/gralloc.h.
      */
-    NATIVE_WINDOW_CONSUMER_USAGE_BITS = 10
+    NATIVE_WINDOW_CONSUMER_USAGE_BITS = 10,
+
+    /**
+     * Transformation that will by applied to buffers by the hwcomposer.
+     * This must not be set or checked by producer endpoints, and will
+     * disable the transform hint set in SurfaceFlinger (see
+     * NATIVE_WINDOW_TRANSFORM_HINT).
+     *
+     * INTENDED USE:
+     * Temporary - Please do not use this.  This is intended only to be used
+     * by the camera's LEGACY mode.
+     *
+     * In situations where a SurfaceFlinger client wishes to set a transform
+     * that is not visible to the producer, and will always be applied in the
+     * hardware composer, the client can set this flag with
+     * native_window_set_buffers_sticky_transform.  This can be used to rotate
+     * and flip buffers consumed by hardware composer without actually changing
+     * the aspect ratio of the buffers produced.
+     */
+    NATIVE_WINDOW_STICKY_TRANSFORM = 11,
 };
 
 /* Valid operations for the (*perform)() hook.
@@ -273,6 +292,8 @@
     NATIVE_WINDOW_API_DISCONNECT            = 14,   /* private */
     NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS = 15, /* private */
     NATIVE_WINDOW_SET_POST_TRANSFORM_CROP   = 16,   /* private */
+    NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM = 17,/* private */
+    NATIVE_WINDOW_SET_SIDEBAND_STREAM       = 18,
 };
 
 /* parameter for NATIVE_WINDOW_[API_][DIS]CONNECT */
@@ -791,6 +812,23 @@
 }
 
 /*
+ * native_window_set_buffers_sticky_transform(..., int transform)
+ * All buffers queued after this call will be displayed transformed according
+ * to the transform parameter specified applied on top of the regular buffer
+ * transform.  Setting this transform will disable the transform hint.
+ *
+ * Temporary - This is only intended to be used by the LEGACY camera mode, do
+ *   not use this for anything else.
+ */
+static inline int native_window_set_buffers_sticky_transform(
+        struct ANativeWindow* window,
+        int transform)
+{
+    return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM,
+            transform);
+}
+
+/*
  * native_window_set_buffers_timestamp(..., int64_t timestamp)
  * All buffers queued after this call will be associated with the timestamp
  * parameter specified. If the timestamp is set to NATIVE_WINDOW_TIMESTAMP_AUTO
@@ -856,6 +894,17 @@
     return anw->dequeueBuffer_DEPRECATED(anw, anb);
 }
 
+/*
+ * native_window_set_sideband_stream(..., native_handle_t*)
+ * Attach a sideband buffer stream to a native window.
+ */
+static inline int native_window_set_sideband_stream(
+        struct ANativeWindow* window,
+        native_handle_t* sidebandHandle)
+{
+    return window->perform(window, NATIVE_WINDOW_SET_SIDEBAND_STREAM,
+            sidebandHandle);
+}
 
 __END_DECLS
 
diff --git a/include/sysutils/NetlinkEvent.h b/include/sysutils/NetlinkEvent.h
index c0a9418..c345cdb 100644
--- a/include/sysutils/NetlinkEvent.h
+++ b/include/sysutils/NetlinkEvent.h
@@ -37,6 +37,8 @@
     const static int NlActionAddressUpdated;
     const static int NlActionAddressRemoved;
     const static int NlActionRdnss;
+    const static int NlActionRouteUpdated;
+    const static int NlActionRouteRemoved;
 
     NetlinkEvent();
     virtual ~NetlinkEvent();
@@ -52,8 +54,11 @@
  protected:
     bool parseBinaryNetlinkMessage(char *buffer, int size);
     bool parseAsciiNetlinkMessage(char *buffer, int size);
-    bool parseIfAddrMessage(int type, struct ifaddrmsg *ifaddr, int rtasize);
-    bool parseNdUserOptMessage(struct nduseroptmsg *msg, int optsize);
+    bool parseIfInfoMessage(const struct nlmsghdr *nh);
+    bool parseIfAddrMessage(const struct nlmsghdr *nh);
+    bool parseUlogPacketMessage(const struct nlmsghdr *nh);
+    bool parseRtMessage(const struct nlmsghdr *nh);
+    bool parseNdUserOptMessage(const struct nlmsghdr *nh);
 };
 
 #endif
diff --git a/include/usbhost/usbhost.h b/include/usbhost/usbhost.h
index 1d67c12..d26e931 100644
--- a/include/usbhost/usbhost.h
+++ b/include/usbhost/usbhost.h
@@ -189,6 +189,13 @@
 int usb_device_connect_kernel_driver(struct usb_device *device,
         unsigned int interface, int connect);
 
+/* Sets the current configuration for the device to the specified configuration */
+int usb_device_set_configuration(struct usb_device *device, int configuration);
+
+/* Sets the specified interface of a USB device */
+int usb_device_set_interface(struct usb_device *device, unsigned int interface,
+                            unsigned int alt_setting);
+
 /* Sends a control message to the specified device on endpoint zero */
 int usb_device_control_transfer(struct usb_device *device,
                             int requestType,
diff --git a/include/utils/BitSet.h b/include/utils/BitSet.h
index f1d68a0..8c61293 100644
--- a/include/utils/BitSet.h
+++ b/include/utils/BitSet.h
@@ -75,19 +75,19 @@
     // Result is undefined if all bits are unmarked.
     inline uint32_t firstMarkedBit() const { return firstMarkedBit(value); }
 
-    static uint32_t firstMarkedBit(uint32_t value) { return __builtin_clzl(value); }
+    static uint32_t firstMarkedBit(uint32_t value) { return clz_checked(value); }
 
     // Finds the first unmarked bit in the set.
     // Result is undefined if all bits are marked.
     inline uint32_t firstUnmarkedBit() const { return firstUnmarkedBit(value); }
 
-    static inline uint32_t firstUnmarkedBit(uint32_t value) { return __builtin_clzl(~ value); }
+    static inline uint32_t firstUnmarkedBit(uint32_t value) { return clz_checked(~ value); }
 
     // Finds the last marked bit in the set.
     // Result is undefined if all bits are unmarked.
     inline uint32_t lastMarkedBit() const { return lastMarkedBit(value); }
 
-    static inline uint32_t lastMarkedBit(uint32_t value) { return 31 - __builtin_ctzl(value); }
+    static inline uint32_t lastMarkedBit(uint32_t value) { return 31 - ctz_checked(value); }
 
     // Finds the first marked bit in the set and clears it.  Returns the bit index.
     // Result is undefined if all bits are unmarked.
@@ -145,6 +145,25 @@
         value |= other.value;
         return *this;
     }
+
+private:
+    // We use these helpers as the signature of __builtin_c{l,t}z has "unsigned int" for the
+    // input, which is only guaranteed to be 16b, not 32. The compiler should optimize this away.
+    static inline uint32_t clz_checked(uint32_t value) {
+        if (sizeof(unsigned int) == sizeof(uint32_t)) {
+            return __builtin_clz(value);
+        } else {
+            return __builtin_clzl(value);
+        }
+    }
+
+    static inline uint32_t ctz_checked(uint32_t value) {
+        if (sizeof(unsigned int) == sizeof(uint32_t)) {
+            return __builtin_ctz(value);
+        } else {
+            return __builtin_ctzl(value);
+        }
+    }
 };
 
 ANDROID_BASIC_TYPES_TRAITS(BitSet32)
diff --git a/include/utils/Condition.h b/include/utils/Condition.h
index e63ba7e..1c99d1a 100644
--- a/include/utils/Condition.h
+++ b/include/utils/Condition.h
@@ -60,7 +60,7 @@
     status_t wait(Mutex& mutex);
     // same with relative timeout
     status_t waitRelative(Mutex& mutex, nsecs_t reltime);
-    // Signal the condition variable, allowing one thread to continue.
+    // Signal the condition variable, allowing exactly one thread to continue.
     void signal();
     // Signal the condition variable, allowing one or all threads to continue.
     void signal(WakeUpType type) {
@@ -132,6 +132,17 @@
 #endif // HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE
 }
 inline void Condition::signal() {
+    /*
+     * POSIX says pthread_cond_signal wakes up "one or more" waiting threads.
+     * However bionic follows the glibc guarantee which wakes up "exactly one"
+     * waiting thread.
+     *
+     * man 3 pthread_cond_signal
+     *   pthread_cond_signal restarts one of the threads that are waiting on
+     *   the condition variable cond. If no threads are waiting on cond,
+     *   nothing happens. If several threads are waiting on cond, exactly one
+     *   is restarted, but it is not specified which.
+     */
     pthread_cond_signal(&mCond);
 }
 inline void Condition::broadcast() {
diff --git a/include/utils/LruCache.h b/include/utils/LruCache.h
index 9248ac9..cd9d7f9 100644
--- a/include/utils/LruCache.h
+++ b/include/utils/LruCache.h
@@ -17,8 +17,8 @@
 #ifndef ANDROID_UTILS_LRU_CACHE_H
 #define ANDROID_UTILS_LRU_CACHE_H
 
+#include <UniquePtr.h>
 #include <utils/BasicHashtable.h>
-#include <utils/UniquePtr.h>
 
 namespace android {
 
@@ -48,6 +48,7 @@
     bool remove(const TKey& key);
     bool removeOldest();
     void clear();
+    const TValue& peekOldestValue();
 
     class Iterator {
     public:
@@ -184,6 +185,14 @@
 }
 
 template <typename TKey, typename TValue>
+const TValue& LruCache<TKey, TValue>::peekOldestValue() {
+    if (mOldest) {
+        return mOldest->value;
+    }
+    return mNullValue;
+}
+
+template <typename TKey, typename TValue>
 void LruCache<TKey, TValue>::clear() {
     if (mListener) {
         for (Entry* p = mOldest; p != NULL; p = p->child) {
diff --git a/include/utils/NativeHandle.h b/include/utils/NativeHandle.h
new file mode 100644
index 0000000..b825168
--- /dev/null
+++ b/include/utils/NativeHandle.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2014 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 ANDROID_NATIVE_HANDLE_H
+#define ANDROID_NATIVE_HANDLE_H
+
+#include <utils/RefBase.h>
+#include <utils/StrongPointer.h>
+
+typedef struct native_handle native_handle_t;
+
+namespace android {
+
+class NativeHandle: public LightRefBase<NativeHandle> {
+public:
+    // Create a refcounted wrapper around a native_handle_t, and declare
+    // whether the wrapper owns the handle (so that it should clean up the
+    // handle upon destruction) or not.
+    // If handle is NULL, no NativeHandle will be created.
+    static sp<NativeHandle> create(native_handle_t* handle, bool ownsHandle);
+
+    const native_handle_t* handle() const {
+        return mHandle;
+    }
+
+private:
+    // for access to the destructor
+    friend class LightRefBase<NativeHandle>;
+
+    NativeHandle(native_handle_t* handle, bool ownsHandle);
+    virtual ~NativeHandle();
+
+    native_handle_t* mHandle;
+    bool mOwnsHandle;
+
+    // non-copyable
+    NativeHandle(const NativeHandle&);
+    NativeHandle& operator=(const NativeHandle&);
+};
+
+} // namespace android
+
+#endif // ANDROID_NATIVE_HANDLE_H
diff --git a/include/utils/RefBase.h b/include/utils/RefBase.h
index cbfe13a..8e15c19 100644
--- a/include/utils/RefBase.h
+++ b/include/utils/RefBase.h
@@ -203,6 +203,13 @@
     mutable volatile int32_t mCount;
 };
 
+// This is a wrapper around LightRefBase that simply enforces a virtual
+// destructor to eliminate the template requirement of LightRefBase
+class VirtualLightRefBase : public LightRefBase<VirtualLightRefBase> {
+public:
+    virtual ~VirtualLightRefBase() {}
+};
+
 // ---------------------------------------------------------------------------
 
 template <typename T>
diff --git a/include/utils/String8.h b/include/utils/String8.h
index ef59470..ecfcf10 100644
--- a/include/utils/String8.h
+++ b/include/utils/String8.h
@@ -130,11 +130,19 @@
             // start, or -1 if not found
             ssize_t             find(const char* other, size_t start = 0) const;
 
+            // return true if this string contains the specified substring
+    inline  bool                contains(const char* other) const;
+
+            // removes all occurrence of the specified substring
+            // returns true if any were found and removed
+            bool                removeAll(const char* other);
+
             void                toLower();
             void                toLower(size_t start, size_t numChars);
             void                toUpper();
             void                toUpper(size_t start, size_t numChars);
 
+
     /*
      * These methods operate on the string as if it were a path name.
      */
@@ -280,6 +288,11 @@
     return SharedBuffer::bufferFromData(mString);
 }
 
+inline bool String8::contains(const char* other) const
+{
+    return find(other) >= 0;
+}
+
 inline String8& String8::operator=(const String8& other)
 {
     setTo(other);
diff --git a/include/utils/UniquePtr.h b/include/utils/UniquePtr.h
deleted file mode 100644
index bc62fe6..0000000
--- a/include/utils/UniquePtr.h
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- */
-
-/* === NOTE === NOTE === NOTE === NOTE === NOTE === NOTE === NOTE === NOTE ===
- *
- * THIS IS A COPY OF libcore/include/UniquePtr.h AND AS SUCH THAT IS THE
- * CANONICAL SOURCE OF THIS FILE. PLEASE KEEP THEM IN SYNC.
- *
- * === NOTE === NOTE === NOTE === NOTE === NOTE === NOTE === NOTE === NOTE ===
- */
-
-#ifndef UNIQUE_PTR_H_included
-#define UNIQUE_PTR_H_included
-
-#include <cstdlib> // For NULL.
-
-// Default deleter for pointer types.
-template <typename T>
-struct DefaultDelete {
-    enum { type_must_be_complete = sizeof(T) };
-    DefaultDelete() {}
-    void operator()(T* p) const {
-        delete p;
-    }
-};
-
-// Default deleter for array types.
-template <typename T>
-struct DefaultDelete<T[]> {
-    enum { type_must_be_complete = sizeof(T) };
-    void operator()(T* p) const {
-        delete[] p;
-    }
-};
-
-// A smart pointer that deletes the given pointer on destruction.
-// Equivalent to C++0x's std::unique_ptr (a combination of boost::scoped_ptr
-// and boost::scoped_array).
-// Named to be in keeping with Android style but also to avoid
-// collision with any other implementation, until we can switch over
-// to unique_ptr.
-// Use thus:
-//   UniquePtr<C> c(new C);
-template <typename T, typename D = DefaultDelete<T> >
-class UniquePtr {
-public:
-    // Construct a new UniquePtr, taking ownership of the given raw pointer.
-    explicit UniquePtr(T* ptr = NULL) : mPtr(ptr) {
-    }
-
-    ~UniquePtr() {
-        reset();
-    }
-
-    // Accessors.
-    T& operator*() const { return *mPtr; }
-    T* operator->() const { return mPtr; }
-    T* get() const { return mPtr; }
-
-    // Returns the raw pointer and hands over ownership to the caller.
-    // The pointer will not be deleted by UniquePtr.
-    T* release() __attribute__((warn_unused_result)) {
-        T* result = mPtr;
-        mPtr = NULL;
-        return result;
-    }
-
-    // Takes ownership of the given raw pointer.
-    // If this smart pointer previously owned a different raw pointer, that
-    // raw pointer will be freed.
-    void reset(T* ptr = NULL) {
-        if (ptr != mPtr) {
-            D()(mPtr);
-            mPtr = ptr;
-        }
-    }
-
-private:
-    // The raw pointer.
-    T* mPtr;
-
-    // Comparing unique pointers is probably a mistake, since they're unique.
-    template <typename T2> bool operator==(const UniquePtr<T2>& p) const;
-    template <typename T2> bool operator!=(const UniquePtr<T2>& p) const;
-
-    // Disallow copy and assignment.
-    UniquePtr(const UniquePtr&);
-    void operator=(const UniquePtr&);
-};
-
-// Partial specialization for array types. Like std::unique_ptr, this removes
-// operator* and operator-> but adds operator[].
-template <typename T, typename D>
-class UniquePtr<T[], D> {
-public:
-    explicit UniquePtr(T* ptr = NULL) : mPtr(ptr) {
-    }
-
-    ~UniquePtr() {
-        reset();
-    }
-
-    T& operator[](size_t i) const {
-        return mPtr[i];
-    }
-    T* get() const { return mPtr; }
-
-    T* release() __attribute__((warn_unused_result)) {
-        T* result = mPtr;
-        mPtr = NULL;
-        return result;
-    }
-
-    void reset(T* ptr = NULL) {
-        if (ptr != mPtr) {
-            D()(mPtr);
-            mPtr = ptr;
-        }
-    }
-
-private:
-    T* mPtr;
-
-    // Disallow copy and assignment.
-    UniquePtr(const UniquePtr&);
-    void operator=(const UniquePtr&);
-};
-
-#if UNIQUE_PTR_TESTS
-
-// Run these tests with:
-// g++ -g -DUNIQUE_PTR_TESTS -x c++ UniquePtr.h && ./a.out
-
-#include <stdio.h>
-
-static void assert(bool b) {
-    if (!b) {
-        fprintf(stderr, "FAIL\n");
-        abort();
-    }
-    fprintf(stderr, "OK\n");
-}
-static int cCount = 0;
-struct C {
-    C() { ++cCount; }
-    ~C() { --cCount; }
-};
-static bool freed = false;
-struct Freer {
-    void operator()(int* p) {
-        assert(*p == 123);
-        free(p);
-        freed = true;
-    }
-};
-
-int main(int argc, char* argv[]) {
-    //
-    // UniquePtr<T> tests...
-    //
-
-    // Can we free a single object?
-    {
-        UniquePtr<C> c(new C);
-        assert(cCount == 1);
-    }
-    assert(cCount == 0);
-    // Does release work?
-    C* rawC;
-    {
-        UniquePtr<C> c(new C);
-        assert(cCount == 1);
-        rawC = c.release();
-    }
-    assert(cCount == 1);
-    delete rawC;
-    // Does reset work?
-    {
-        UniquePtr<C> c(new C);
-        assert(cCount == 1);
-        c.reset(new C);
-        assert(cCount == 1);
-    }
-    assert(cCount == 0);
-
-    //
-    // UniquePtr<T[]> tests...
-    //
-
-    // Can we free an array?
-    {
-        UniquePtr<C[]> cs(new C[4]);
-        assert(cCount == 4);
-    }
-    assert(cCount == 0);
-    // Does release work?
-    {
-        UniquePtr<C[]> c(new C[4]);
-        assert(cCount == 4);
-        rawC = c.release();
-    }
-    assert(cCount == 4);
-    delete[] rawC;
-    // Does reset work?
-    {
-        UniquePtr<C[]> c(new C[4]);
-        assert(cCount == 4);
-        c.reset(new C[2]);
-        assert(cCount == 2);
-    }
-    assert(cCount == 0);
-
-    //
-    // Custom deleter tests...
-    //
-    assert(!freed);
-    {
-        UniquePtr<int, Freer> i(reinterpret_cast<int*>(malloc(sizeof(int))));
-        *i = 123;
-    }
-    assert(freed);
-    return 0;
-}
-#endif
-
-#endif  // UNIQUE_PTR_H_included
diff --git a/init/builtins.c b/init/builtins.c
index b32981e..c192551 100644
--- a/init/builtins.c
+++ b/init/builtins.c
@@ -48,7 +48,7 @@
 
 #include <private/android_filesystem_config.h>
 
-void add_environment(const char *name, const char *value);
+int add_environment(const char *name, const char *value);
 
 extern int init_module(void *, unsigned long, const char *);
 
@@ -261,8 +261,7 @@
 
 int do_export(int nargs, char **args)
 {
-    add_environment(args[1], args[2]);
-    return 0;
+    return add_environment(args[1], args[2]);
 }
 
 int do_hostname(int nargs, char **args)
@@ -474,6 +473,27 @@
 
 }
 
+static int wipe_data_via_recovery()
+{
+    mkdir("/cache/recovery", 0700);
+    int fd = open("/cache/recovery/command", O_RDWR|O_CREAT|O_TRUNC, 0600);
+    if (fd >= 0) {
+        write(fd, "--wipe_data\n", strlen("--wipe_data\n") + 1);
+        write(fd, "--reason=wipe_data_via_recovery\n", strlen("--reason=wipe_data_via_recovery\n") + 1);
+        close(fd);
+    } else {
+        ERROR("could not open /cache/recovery/command\n");
+        return -1;
+    }
+    android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
+    while (1) { pause(); }  // never reached
+}
+
+
+/*
+ * This function might request a reboot, in which case it will
+ * not return.
+ */
 int do_mount_all(int nargs, char **args)
 {
     pid_t pid;
@@ -496,7 +516,12 @@
     pid = fork();
     if (pid > 0) {
         /* Parent.  Wait for the child to return */
-        waitpid(pid, &status, 0);
+        int wp_ret = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
+        if (wp_ret < 0) {
+            /* Unexpected error code. We will continue anyway. */
+            NOTICE("waitpid failed rc=%d, errno=%d\n", wp_ret, errno);
+        }
+
         if (WIFEXITED(status)) {
             ret = WEXITSTATUS(status);
         } else {
@@ -511,23 +536,32 @@
         if (child_ret == -1) {
             ERROR("fs_mgr_mount_all returned an error\n");
         }
-        exit(child_ret);
+        _exit(child_ret);
     } else {
         /* fork failed, return an error */
         return -1;
     }
 
-    /* ret is 1 if the device is encrypted, 0 if not, and -1 on error */
-    if (ret == 1) {
+    if (ret == FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION) {
+        property_set("vold.decrypt", "trigger_encryption");
+    } else if (ret == FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED) {
         property_set("ro.crypto.state", "encrypted");
-        property_set("vold.decrypt", "1");
-    } else if (ret == 0) {
+        property_set("vold.decrypt", "trigger_default_encryption");
+    } else if (ret == FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) {
         property_set("ro.crypto.state", "unencrypted");
         /* If fs_mgr determined this is an unencrypted device, then trigger
          * that action.
          */
         action_for_each_trigger("nonencrypted", action_add_queue_tail);
+    } else if (ret == FS_MGR_MNTALL_DEV_NEEDS_RECOVERY) {
+        /* Setup a wipe via recovery, and reboot into recovery */
+        ERROR("fs_mgr_mount_all suggested recovery, so wiping data via recovery.\n");
+        ret = wipe_data_via_recovery();
+        /* If reboot worked, there is no return. */
+    } else if (ret > 0) {
+        ERROR("fs_mgr_mount_all returned unexpected error %d\n", ret);
     }
+    /* else ... < 0: error */
 
     return ret;
 }
diff --git a/init/devices.c b/init/devices.c
index e27c311..1012fee 100644
--- a/init/devices.c
+++ b/init/devices.c
@@ -942,7 +942,7 @@
     }
 }
 
-#define UEVENT_MSG_LEN  1024
+#define UEVENT_MSG_LEN  2048
 void handle_device_fd()
 {
     char msg[UEVENT_MSG_LEN+2];
diff --git a/init/init.c b/init/init.c
index e4ac1cf..bd1db7a 100644
--- a/init/init.c
+++ b/init/init.c
@@ -96,11 +96,24 @@
 /* add_environment - add "key=value" to the current environment */
 int add_environment(const char *key, const char *val)
 {
-    int n;
+    size_t n;
+    size_t key_len = strlen(key);
 
-    for (n = 0; n < 31; n++) {
-        if (!ENV[n]) {
-            size_t len = strlen(key) + strlen(val) + 2;
+    /* The last environment entry is reserved to terminate the list */
+    for (n = 0; n < (ARRAY_SIZE(ENV) - 1); n++) {
+
+        /* Delete any existing entry for this key */
+        if (ENV[n] != NULL) {
+            size_t entry_key_len = strcspn(ENV[n], "=");
+            if ((entry_key_len == key_len) && (strncmp(ENV[n], key, entry_key_len) == 0)) {
+                free((char*)ENV[n]);
+                ENV[n] = NULL;
+            }
+        }
+
+        /* Add entry if a free slot is available */
+        if (ENV[n] == NULL) {
+            size_t len = key_len + strlen(val) + 2;
             char *entry = malloc(len);
             snprintf(entry, len, "%s=%s", key, val);
             ENV[n] = entry;
@@ -108,7 +121,9 @@
         }
     }
 
-    return 1;
+    ERROR("No env. room to store: '%s':'%s'\n", key, val);
+
+    return -1;
 }
 
 static void zap_stdio(void)
@@ -802,27 +817,21 @@
      * that /data/local.prop cannot interfere with them.
      */
     start_property_service();
+    if (get_property_set_fd() < 0) {
+        ERROR("start_property_service() failed\n");
+        exit(1);
+    }
+
     return 0;
 }
 
 static int signal_init_action(int nargs, char **args)
 {
     signal_init();
-    return 0;
-}
-
-static int check_startup_action(int nargs, char **args)
-{
-    /* make sure we actually have all the pieces we need */
-    if ((get_property_set_fd() < 0) ||
-        (get_signal_fd() < 0)) {
-        ERROR("init startup failure\n");
+    if (get_signal_fd() < 0) {
+        ERROR("signal_init() failed\n");
         exit(1);
     }
-
-        /* signal that we hit this point */
-    unlink("/dev/.booting");
-
     return 0;
 }
 
@@ -1083,7 +1092,6 @@
     queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
     queue_builtin_action(property_service_init_action, "property_service_init");
     queue_builtin_action(signal_init_action, "signal_init");
-    queue_builtin_action(check_startup_action, "check_startup");
 
     /* Don't mount filesystems or start core system services if in charger mode. */
     if (is_charger) {
@@ -1092,7 +1100,7 @@
         action_for_each_trigger("late-init", action_add_queue_tail);
     }
 
-        /* run all property triggers based on current state of the properties */
+    /* run all property triggers based on current state of the properties */
     queue_builtin_action(queue_property_triggers_action, "queue_property_triggers");
 
 
diff --git a/init/property_service.c b/init/property_service.c
index d112699..1902b77 100644
--- a/init/property_service.c
+++ b/init/property_service.c
@@ -24,6 +24,7 @@
 #include <dirent.h>
 #include <limits.h>
 #include <errno.h>
+#include <sys/poll.h>
 
 #include <cutils/misc.h>
 #include <cutils/sockets.h>
@@ -181,7 +182,6 @@
 static bool is_legal_property_name(const char* name, size_t namelen)
 {
     size_t i;
-    bool previous_was_dot = false;
     if (namelen >= PROP_NAME_MAX) return false;
     if (namelen < 1) return false;
     if (name[0] == '.') return false;
@@ -191,11 +191,10 @@
     /* Don't allow ".." to appear in a property name */
     for (i = 0; i < namelen; i++) {
         if (name[i] == '.') {
-            if (previous_was_dot == true) return false;
-            previous_was_dot = true;
+            // i=0 is guaranteed to never have a dot. See above.
+            if (name[i-1] == '.') return false;
             continue;
         }
-        previous_was_dot = false;
         if (name[i] == '_' || name[i] == '-') continue;
         if (name[i] >= 'a' && name[i] <= 'z') continue;
         if (name[i] >= 'A' && name[i] <= 'Z') continue;
@@ -268,6 +267,9 @@
     socklen_t addr_size = sizeof(addr);
     socklen_t cr_size = sizeof(cr);
     char * source_ctx = NULL;
+    struct pollfd ufds[1];
+    const int timeout_ms = 2 * 1000;  /* Default 2 sec timeout for caller to send property. */
+    int nr;
 
     if ((s = accept(property_set_fd, (struct sockaddr *) &addr, &addr_size)) < 0) {
         return;
@@ -280,7 +282,21 @@
         return;
     }
 
-    r = TEMP_FAILURE_RETRY(recv(s, &msg, sizeof(msg), 0));
+    ufds[0].fd = s;
+    ufds[0].events = POLLIN;
+    ufds[0].revents = 0;
+    nr = TEMP_FAILURE_RETRY(poll(ufds, 1, timeout_ms));
+    if (nr == 0) {
+        ERROR("sys_prop: timeout waiting for uid=%d to send property message.\n", cr.uid);
+        close(s);
+        return;
+    } else if (nr < 0) {
+        ERROR("sys_prop: error waiting for uid=%d to send property message. err=%d %s\n", cr.uid, errno, strerror(errno));
+        close(s);
+        return;
+    }
+
+    r = TEMP_FAILURE_RETRY(recv(s, &msg, sizeof(msg), MSG_DONTWAIT));
     if(r != sizeof(prop_msg)) {
         ERROR("sys_prop: mis-match msg size received: %d expected: %zu errno: %d\n",
               r, sizeof(prop_msg), errno);
diff --git a/init/readme.txt b/init/readme.txt
index 613a9e9..26be536 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -257,9 +257,9 @@
   or the timeout has been reached. If timeout is not specified it
   currently defaults to five seconds.
 
-write <path> <string> [ <string> ]*
-   Open the file at <path> and write one or more strings
-   to it with write(2)
+write <path> <string>
+   Open the file at <path> and write a string to it with write(2)
+   without appending.
 
 
 Properties
diff --git a/libbacktrace/BacktraceMap.cpp b/libbacktrace/BacktraceMap.cpp
index 0056f4b..f38e484 100644
--- a/libbacktrace/BacktraceMap.cpp
+++ b/libbacktrace/BacktraceMap.cpp
@@ -137,7 +137,7 @@
 #if defined(__APPLE__)
 // Corkscrew and libunwind don't compile on the mac, so create a generic
 // map object.
-BacktraceMap* BacktraceMap::Create(pid_t pid) {
+BacktraceMap* BacktraceMap::Create(pid_t pid, bool uncached) {
   BacktraceMap* map = new BacktraceMap(pid);
   if (!map->Build()) {
     delete map;
diff --git a/libbacktrace/UnwindMap.cpp b/libbacktrace/UnwindMap.cpp
index 4f9831b..387d768 100644
--- a/libbacktrace/UnwindMap.cpp
+++ b/libbacktrace/UnwindMap.cpp
@@ -130,9 +130,13 @@
 //-------------------------------------------------------------------------
 // BacktraceMap create function.
 //-------------------------------------------------------------------------
-BacktraceMap* BacktraceMap::Create(pid_t pid) {
+BacktraceMap* BacktraceMap::Create(pid_t pid, bool uncached) {
   BacktraceMap* map;
-  if (pid == getpid()) {
+
+  if (uncached) {
+    // Force use of the base class to parse the maps when this call is made.
+    map = new BacktraceMap(pid);
+  } else if (pid == getpid()) {
     map = new UnwindMapLocal();
   } else {
     map = new UnwindMap(pid);
diff --git a/libbacktrace/map_info.c b/libbacktrace/map_info.c
new file mode 100644
index 0000000..073b24a
--- /dev/null
+++ b/libbacktrace/map_info.c
@@ -0,0 +1,173 @@
+/*
+ * 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 <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <log/log.h>
+#include <sys/time.h>
+
+#include <backtrace/backtrace.h>
+
+#if defined(__APPLE__)
+
+// Mac OS vmmap(1) output:
+// __TEXT                 0009f000-000a1000 [    8K     8K] r-x/rwx SM=COW  /Volumes/android/dalvik-dev/out/host/darwin-x86/bin/libcorkscrew_test\n
+// 012345678901234567890123456789012345678901234567890123456789
+// 0         1         2         3         4         5
+static backtrace_map_info_t* parse_vmmap_line(const char* line) {
+  unsigned long int start;
+  unsigned long int end;
+  char permissions[4];
+  int name_pos;
+  if (sscanf(line, "%*21c %lx-%lx [%*13c] %3c/%*3c SM=%*3c  %n",
+             &start, &end, permissions, &name_pos) != 3) {
+    return NULL;
+  }
+
+  const char* name = line + name_pos;
+  size_t name_len = strlen(name);
+
+  backtrace_map_info_t* mi = calloc(1, sizeof(backtrace_map_info_t) + name_len);
+  if (mi != NULL) {
+    mi->start = start;
+    mi->end = end;
+    mi->is_readable = permissions[0] == 'r';
+    mi->is_writable = permissions[1] == 'w';
+    mi->is_executable = permissions[2] == 'x';
+    memcpy(mi->name, name, name_len);
+    mi->name[name_len - 1] = '\0';
+    ALOGV("Parsed map: start=0x%08x, end=0x%08x, "
+          "is_readable=%d, is_writable=%d is_executable=%d, name=%s",
+          mi->start, mi->end,
+          mi->is_readable, mi->is_writable, mi->is_executable, mi->name);
+  }
+  return mi;
+}
+
+backtrace_map_info_t* backtrace_create_map_info_list(pid_t pid) {
+  char cmd[1024];
+  if (pid < 0) {
+    pid = getpid();
+  }
+  snprintf(cmd, sizeof(cmd), "vmmap -w -resident -submap -allSplitLibs -interleaved %d", pid);
+  FILE* fp = popen(cmd, "r");
+  if (fp == NULL) {
+    return NULL;
+  }
+
+  char line[1024];
+  backtrace_map_info_t* milist = NULL;
+  while (fgets(line, sizeof(line), fp) != NULL) {
+    backtrace_map_info_t* mi = parse_vmmap_line(line);
+    if (mi != NULL) {
+      mi->next = milist;
+      milist = mi;
+    }
+  }
+  pclose(fp);
+  return milist;
+}
+
+#else
+
+// Linux /proc/<pid>/maps lines:
+// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419   /system/lib/libcomposer.so\n
+// 012345678901234567890123456789012345678901234567890123456789
+// 0         1         2         3         4         5
+static backtrace_map_info_t* parse_maps_line(const char* line)
+{
+  unsigned long int start;
+  unsigned long int end;
+  char permissions[5];
+  int name_pos;
+  if (sscanf(line, "%lx-%lx %4s %*x %*x:%*x %*d%n", &start, &end,
+             permissions, &name_pos) != 3) {
+    return NULL;
+  }
+
+  while (isspace(line[name_pos])) {
+    name_pos += 1;
+  }
+  const char* name = line + name_pos;
+  size_t name_len = strlen(name);
+  if (name_len && name[name_len - 1] == '\n') {
+    name_len -= 1;
+  }
+
+  backtrace_map_info_t* mi = calloc(1, sizeof(backtrace_map_info_t) + name_len + 1);
+  if (mi) {
+    mi->start = start;
+    mi->end = end;
+    mi->is_readable = strlen(permissions) == 4 && permissions[0] == 'r';
+    mi->is_writable = strlen(permissions) == 4 && permissions[1] == 'w';
+    mi->is_executable = strlen(permissions) == 4 && permissions[2] == 'x';
+    memcpy(mi->name, name, name_len);
+    mi->name[name_len] = '\0';
+    ALOGV("Parsed map: start=0x%08x, end=0x%08x, "
+          "is_readable=%d, is_writable=%d, is_executable=%d, name=%s",
+          mi->start, mi->end,
+          mi->is_readable, mi->is_writable, mi->is_executable, mi->name);
+  }
+  return mi;
+}
+
+backtrace_map_info_t* backtrace_create_map_info_list(pid_t tid) {
+  char path[PATH_MAX];
+  char line[1024];
+  FILE* fp;
+  backtrace_map_info_t* milist = NULL;
+
+  if (tid < 0) {
+    tid = getpid();
+  }
+  snprintf(path, PATH_MAX, "/proc/%d/maps", tid);
+  fp = fopen(path, "r");
+  if (fp) {
+    while(fgets(line, sizeof(line), fp)) {
+      backtrace_map_info_t* mi = parse_maps_line(line);
+      if (mi) {
+        mi->next = milist;
+        milist = mi;
+      }
+    }
+    fclose(fp);
+  }
+  return milist;
+}
+
+#endif
+
+void backtrace_destroy_map_info_list(backtrace_map_info_t* milist) {
+  while (milist) {
+    backtrace_map_info_t* next = milist->next;
+    free(milist);
+    milist = next;
+  }
+}
+
+const backtrace_map_info_t* backtrace_find_map_info(
+    const backtrace_map_info_t* milist, uintptr_t addr) {
+  const backtrace_map_info_t* mi = milist;
+  while (mi && !(addr >= mi->start && addr < mi->end)) {
+    mi = mi->next;
+  }
+  return mi;
+}
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index 933a77b..b016a42 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -86,19 +86,6 @@
 include $(BUILD_HOST_STATIC_LIBRARY)
 
 
-# Static library for host, 64-bit
-# ========================================================
-include $(CLEAR_VARS)
-LOCAL_MODULE := lib64cutils
-LOCAL_SRC_FILES := $(commonSources) $(commonHostSources) dlmalloc_stubs.c
-LOCAL_STATIC_LIBRARIES := lib64log
-LOCAL_CFLAGS += $(hostSmpFlag) -m64
-ifneq ($(HOST_OS),windows)
-LOCAL_CFLAGS += -Werror
-endif
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-include $(BUILD_HOST_STATIC_LIBRARY)
-
 # Tests for host
 # ========================================================
 include $(CLEAR_VARS)
diff --git a/libcutils/debugger.c b/libcutils/debugger.c
index 056de5d..4035ee1 100644
--- a/libcutils/debugger.c
+++ b/libcutils/debugger.c
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+#include <stdbool.h>
+#include <fcntl.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
@@ -21,70 +24,129 @@
 #include <cutils/debugger.h>
 #include <cutils/sockets.h>
 
-int dump_tombstone(pid_t tid, char* pathbuf, size_t pathlen) {
-    int s = socket_local_client(DEBUGGER_SOCKET_NAME,
-            ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
-    if (s < 0) {
-        return -1;
-    }
+#if defined(__LP64__)
+#include <elf.h>
 
-    debugger_msg_t msg;
-    memset(&msg, 0, sizeof(msg));
+static bool is32bit(pid_t tid) {
+  char* exeline;
+  if (asprintf(&exeline, "/proc/%d/exe", tid) == -1) {
+    return false;
+  }
+  int fd = open(exeline, O_RDONLY | O_CLOEXEC);
+  free(exeline);
+  if (fd == -1) {
+    return false;
+  }
+
+  char ehdr[EI_NIDENT];
+  ssize_t bytes = read(fd, &ehdr, sizeof(ehdr));
+  close(fd);
+  if (bytes != (ssize_t) sizeof(ehdr) || memcmp(ELFMAG, ehdr, SELFMAG) != 0) {
+    return false;
+  }
+  if (ehdr[EI_CLASS] == ELFCLASS32) {
+    return true;
+  }
+  return false;
+}
+#endif
+
+static int send_request(int sock_fd, void* msg_ptr, size_t msg_len) {
+  int result = 0;
+  if (TEMP_FAILURE_RETRY(write(sock_fd, msg_ptr, msg_len)) != (ssize_t) msg_len) {
+    result = -1;
+  } else {
+    char ack;
+    if (TEMP_FAILURE_RETRY(read(sock_fd, &ack, 1)) != 1) {
+      result = -1;
+    }
+  }
+  return result;
+}
+
+static int make_dump_request(debugger_action_t action, pid_t tid) {
+  const char* socket_name;
+  debugger_msg_t msg;
+  size_t msg_len;
+  void* msg_ptr;
+
+#if defined(__LP64__)
+  debugger32_msg_t msg32;
+  if (is32bit(tid)) {
+    msg_len = sizeof(debugger32_msg_t);
+    memset(&msg32, 0, msg_len);
+    msg32.tid = tid;
+    msg32.action = action;
+    msg_ptr = &msg32;
+
+    socket_name = DEBUGGER32_SOCKET_NAME;
+  } else
+#endif
+  {
+    msg_len = sizeof(debugger_msg_t);
+    memset(&msg, 0, msg_len);
     msg.tid = tid;
-    msg.action = DEBUGGER_ACTION_DUMP_TOMBSTONE;
+    msg.action = action;
+    msg_ptr = &msg;
 
-    int result = 0;
-    if (TEMP_FAILURE_RETRY(write(s, &msg, sizeof(msg))) != sizeof(msg)) {
-        result = -1;
-    } else {
-        char ack;
-        if (TEMP_FAILURE_RETRY(read(s, &ack, 1)) != 1) {
-            result = -1;
-        } else {
-            if (pathbuf && pathlen) {
-                ssize_t n = TEMP_FAILURE_RETRY(read(s, pathbuf, pathlen - 1));
-                if (n <= 0) {
-                    result = -1;
-                } else {
-                    pathbuf[n] = '\0';
-                }
-            }
-        }
-    }
-    TEMP_FAILURE_RETRY(close(s));
-    return result;
+    socket_name = DEBUGGER_SOCKET_NAME;
+  }
+
+  int sock_fd = socket_local_client(socket_name, ANDROID_SOCKET_NAMESPACE_ABSTRACT,
+      SOCK_STREAM | SOCK_CLOEXEC);
+  if (sock_fd < 0) {
+    return -1;
+  }
+
+  if (send_request(sock_fd, msg_ptr, msg_len) < 0) {
+    TEMP_FAILURE_RETRY(close(sock_fd));
+    return -1;
+  }
+
+  return sock_fd;
 }
 
 int dump_backtrace_to_file(pid_t tid, int fd) {
-    int s = socket_local_client(DEBUGGER_SOCKET_NAME,
-            ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
-    if (s < 0) {
-        return -1;
-    }
+  int sock_fd = make_dump_request(DEBUGGER_ACTION_DUMP_BACKTRACE, tid);
+  if (sock_fd < 0) {
+    return -1;
+  }
 
-    debugger_msg_t msg;
-    memset(&msg, 0, sizeof(msg));
-    msg.tid = tid;
-    msg.action = DEBUGGER_ACTION_DUMP_BACKTRACE;
-
-    int result = 0;
-    if (TEMP_FAILURE_RETRY(write(s, &msg, sizeof(msg))) != sizeof(msg)) {
-        result = -1;
-    } else {
-        char ack;
-        if (TEMP_FAILURE_RETRY(read(s, &ack, 1)) != 1) {
-            result = -1;
-        } else {
-            char buffer[4096];
-            ssize_t n;
-            while ((n = TEMP_FAILURE_RETRY(read(s, buffer, sizeof(buffer)))) > 0) {
-                if (TEMP_FAILURE_RETRY(write(fd, buffer, n)) != n) {
-                    result = -1;
-                    break;
-                }
-            }
-        }
+  /* Write the data read from the socket to the fd. */
+  int result = 0;
+  char buffer[1024];
+  ssize_t n;
+  while ((n = TEMP_FAILURE_RETRY(read(sock_fd, buffer, sizeof(buffer)))) > 0) {
+    if (TEMP_FAILURE_RETRY(write(fd, buffer, n)) != n) {
+      result = -1;
+      break;
     }
-    TEMP_FAILURE_RETRY(close(s));
-    return result;
+  }
+  TEMP_FAILURE_RETRY(close(sock_fd));
+  return result;
+}
+
+int dump_tombstone(pid_t tid, char* pathbuf, size_t pathlen) {
+  int sock_fd = make_dump_request(DEBUGGER_ACTION_DUMP_TOMBSTONE, tid);
+  if (sock_fd < 0) {
+    return -1;
+  }
+
+  /* Read the tombstone file name. */
+  char buffer[100]; /* This is larger than the largest tombstone path. */
+  int result = 0;
+  ssize_t n = TEMP_FAILURE_RETRY(read(sock_fd, buffer, sizeof(buffer) - 1));
+  if (n <= 0) {
+    result = -1;
+  } else {
+    if (pathbuf && pathlen) {
+      if (n >= (ssize_t) pathlen) {
+        n = pathlen - 1;
+      }
+      buffer[n] = '\0';
+      memcpy(pathbuf, buffer, n + 1);
+    }
+  }
+  TEMP_FAILURE_RETRY(close(sock_fd));
+  return result;
 }
diff --git a/libcutils/fs.c b/libcutils/fs.c
index 286a8eb..45c7add 100644
--- a/libcutils/fs.c
+++ b/libcutils/fs.c
@@ -212,7 +212,7 @@
 
             /* Yay, segment is ready for us to step into */
             int next_fd;
-            if ((next_fd = openat(fd, segment, 0)) == -1) {
+            if ((next_fd = openat(fd, segment, O_NOFOLLOW | O_CLOEXEC)) == -1) {
                 ALOGE("Failed to openat(%s): %s", buf, strerror(errno));
                 res = -errno;
                 goto done_close;
diff --git a/libcutils/sched_policy.c b/libcutils/sched_policy.c
index 9f092d6..2acc3c3 100644
--- a/libcutils/sched_policy.c
+++ b/libcutils/sched_policy.c
@@ -39,21 +39,20 @@
 
 #if defined(HAVE_ANDROID_OS) && defined(HAVE_SCHED_H) && defined(HAVE_PTHREADS)
 
-#include <sched.h>
 #include <pthread.h>
-
-#ifndef SCHED_NORMAL
-  #define SCHED_NORMAL 0
-#endif
-
-#ifndef SCHED_BATCH
-  #define SCHED_BATCH 3
-#endif
+#include <sched.h>
+#include <sys/prctl.h>
 
 #define POLICY_DEBUG 0
 
 #define CAN_SET_SP_SYSTEM 0 // non-zero means to implement set_sched_policy(tid, SP_SYSTEM)
 
+// This prctl is only available in Android kernels.
+#define PR_SET_TIMERSLACK_PID 41
+
+// timer slack value in nS enforced when the thread moves to background
+#define TIMER_SLACK_BG 40000000
+
 static pthread_once_t the_once = PTHREAD_ONCE_INIT;
 
 static int __sys_supports_schedgroups = -1;
@@ -325,6 +324,8 @@
                            &param);
     }
 
+    prctl(PR_SET_TIMERSLACK_PID, policy == SP_BACKGROUND ? TIMER_SLACK_BG : 0, tid);
+
     return 0;
 }
 
diff --git a/libcutils/str_parms.c b/libcutils/str_parms.c
index 2e3ce9f..dfe8c4b 100644
--- a/libcutils/str_parms.c
+++ b/libcutils/str_parms.c
@@ -262,6 +262,10 @@
     return ret;
 }
 
+int str_parms_has_key(struct str_parms *str_parms, const char *key) {
+    return hashmapGet(str_parms->map, (void *)key) != NULL;
+}
+
 int str_parms_get_str(struct str_parms *str_parms, const char *key, char *val,
                       int len)
 {
diff --git a/libdiskconfig/config_mbr.c b/libdiskconfig/config_mbr.c
index 7641b29..7b6ca1c 100644
--- a/libdiskconfig/config_mbr.c
+++ b/libdiskconfig/config_mbr.c
@@ -208,6 +208,26 @@
 }
 
 
+static struct write_list *
+mk_mbr_sig()
+{
+    struct write_list *item;
+    if (!(item = alloc_wl(sizeof(uint16_t)))) {
+        ALOGE("Unable to allocate memory for MBR signature.");
+        return NULL;
+    }
+
+    {
+        /* DO NOT DEREFERENCE */
+        struct pc_boot_record *mbr = (void *)PC_MBR_DISK_OFFSET;
+        /* grab the offset in mbr where to write mbr signature. */
+        item->offset = (loff_t)((uintptr_t)((uint8_t *)(&mbr->mbr_sig)));
+    }
+
+    *((uint16_t*)item->data) = PC_BIOS_BOOT_SIG;
+    return item;
+}
+
 struct write_list *
 config_mbr(struct disk_info *dinfo)
 {
@@ -276,6 +296,13 @@
         wlist_add(&wr_list, temp_wr);
     }
 
+    if ((temp_wr = mk_mbr_sig()))
+        wlist_add(&wr_list, temp_wr);
+    else {
+        ALOGE("Cannot set MBR signature");
+        goto fail;
+    }
+
     return wr_list;
 
 nospace:
diff --git a/liblog/Android.mk b/liblog/Android.mk
index a7eead9..a4e5f5e 100644
--- a/liblog/Android.mk
+++ b/liblog/Android.mk
@@ -71,14 +71,6 @@
 include $(BUILD_HOST_SHARED_LIBRARY)
 
 
-# Static library for host, 64-bit
-# ========================================================
-include $(CLEAR_VARS)
-LOCAL_MODULE := lib64log
-LOCAL_SRC_FILES := $(liblog_host_sources)
-LOCAL_CFLAGS := -DFAKE_LOG_DEVICE=1 -m64 -Werror
-include $(BUILD_HOST_STATIC_LIBRARY)
-
 # Shared and static library for target
 # ========================================================
 include $(CLEAR_VARS)
diff --git a/liblog/logd_write.c b/liblog/logd_write.c
index 3171c78..b2668ce 100644
--- a/liblog/logd_write.c
+++ b/liblog/logd_write.c
@@ -31,6 +31,10 @@
 #include <time.h>
 #include <unistd.h>
 
+#ifdef __BIONIC__
+#include <android/set_abort_message.h>
+#endif
+
 #include <log/logd.h>
 #include <log/logger.h>
 #include <log/log_read.h>
@@ -54,7 +58,6 @@
 #endif
 
 #if FAKE_LOG_DEVICE
-#define WEAK __attribute__((weak))
 static int log_fds[(int)LOG_ID_MAX] = { -1, -1, -1, -1, -1 };
 #else
 static int logd_fd = -1;
@@ -270,7 +273,7 @@
     [LOG_ID_CRASH] = "crash"
 };
 
-const WEAK char *android_log_id_to_name(log_id_t log_id)
+const char *android_log_id_to_name(log_id_t log_id)
 {
     if (log_id >= LOG_ID_MAX) {
         log_id = LOG_ID_MAIN;
@@ -333,8 +336,7 @@
 
 #if __BIONIC__
     if (prio == ANDROID_LOG_FATAL) {
-        extern void __android_set_abort_message(const char*);
-        __android_set_abort_message(msg);
+        android_set_abort_message(msg);
     }
 #endif
 
diff --git a/liblog/logd_write_kern.c b/liblog/logd_write_kern.c
index 1ed5ecf..ae621cb 100644
--- a/liblog/logd_write_kern.c
+++ b/liblog/logd_write_kern.c
@@ -28,6 +28,10 @@
 #include <time.h>
 #include <unistd.h>
 
+#ifdef __BIONIC__
+#include <android/set_abort_message.h>
+#endif
+
 #include <log/log.h>
 #include <log/logd.h>
 #include <log/logger.h>
@@ -177,8 +181,7 @@
 
 #if __BIONIC__
     if (prio == ANDROID_LOG_FATAL) {
-        extern void __android_set_abort_message(const char*);
-        __android_set_abort_message(msg);
+        android_set_abort_message(msg);
     }
 #endif
 
diff --git a/libnativebridge/Android.mk b/libnativebridge/Android.mk
new file mode 100644
index 0000000..6c2e43e
--- /dev/null
+++ b/libnativebridge/Android.mk
@@ -0,0 +1,40 @@
+LOCAL_PATH:= $(call my-dir)
+
+NATIVE_BRIDGE_COMMON_SRC_FILES := \
+  native_bridge.cc
+
+# Shared library for target
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= libnativebridge
+
+LOCAL_SRC_FILES:= $(NATIVE_BRIDGE_COMMON_SRC_FILES)
+LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_CLANG := true
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_CFLAGS := -Werror -Wall
+LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected
+LOCAL_LDFLAGS := -ldl
+LOCAL_MULTILIB := both
+
+include $(BUILD_SHARED_LIBRARY)
+
+# Shared library for host
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= libnativebridge
+
+LOCAL_SRC_FILES:= $(NATIVE_BRIDGE_COMMON_SRC_FILES)
+LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_CLANG := true
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_CFLAGS := -Werror -Wall
+LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected
+LOCAL_LDFLAGS := -ldl
+LOCAL_MULTILIB := both
+
+include $(BUILD_HOST_SHARED_LIBRARY)
+
+include $(LOCAL_PATH)/tests/Android.mk
\ No newline at end of file
diff --git a/libnativebridge/native_bridge.cc b/libnativebridge/native_bridge.cc
new file mode 100644
index 0000000..3facedd
--- /dev/null
+++ b/libnativebridge/native_bridge.cc
@@ -0,0 +1,435 @@
+/*
+ * Copyright (C) 2014 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 "nativebridge/native_bridge.h"
+
+#include <cstring>
+#include <cutils/log.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+
+
+namespace android {
+
+// Environment values required by the apps running with native bridge.
+struct NativeBridgeRuntimeValues {
+    const char* os_arch;
+    const char* cpu_abi;
+    const char* cpu_abi2;
+    const char* *supported_abis;
+    int32_t abi_count;
+};
+
+// The symbol name exposed by native-bridge with the type of NativeBridgeCallbacks.
+static constexpr const char* kNativeBridgeInterfaceSymbol = "NativeBridgeItf";
+
+enum class NativeBridgeState {
+  kNotSetup,                        // Initial state.
+  kOpened,                          // After successful dlopen.
+  kInitialized,                     // After successful initialization.
+  kClosed                           // Closed or errors.
+};
+
+static const char* kNotSetupString = "kNotSetup";
+static const char* kOpenedString = "kOpened";
+static const char* kInitializedString = "kInitialized";
+static const char* kClosedString = "kClosed";
+
+static const char* GetNativeBridgeStateString(NativeBridgeState state) {
+  switch (state) {
+    case NativeBridgeState::kNotSetup:
+      return kNotSetupString;
+
+    case NativeBridgeState::kOpened:
+      return kOpenedString;
+
+    case NativeBridgeState::kInitialized:
+      return kInitializedString;
+
+    case NativeBridgeState::kClosed:
+      return kClosedString;
+  }
+}
+
+// Current state of the native bridge.
+static NativeBridgeState state = NativeBridgeState::kNotSetup;
+
+// Whether we had an error at some point.
+static bool had_error = false;
+
+// Handle of the loaded library.
+static void* native_bridge_handle = nullptr;
+// Pointer to the callbacks. Available as soon as LoadNativeBridge succeeds, but only initialized
+// later.
+static NativeBridgeCallbacks* callbacks = nullptr;
+// Callbacks provided by the environment to the bridge. Passed to LoadNativeBridge.
+static const NativeBridgeRuntimeCallbacks* runtime_callbacks = nullptr;
+
+// The app's data directory.
+static char* app_data_dir = nullptr;
+
+static constexpr uint32_t kNativeBridgeCallbackVersion = 1;
+
+// Characters allowed in a native bridge filename. The first character must
+// be in [a-zA-Z] (expected 'l' for "libx"). The rest must be in [a-zA-Z0-9._-].
+static bool CharacterAllowed(char c, bool first) {
+  if (first) {
+    return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');
+  } else {
+    return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') ||
+           (c == '.') || (c == '_') || (c == '-');
+  }
+}
+
+// We only allow simple names for the library. It is supposed to be a file in
+// /system/lib or /vendor/lib. Only allow a small range of characters, that is
+// names consisting of [a-zA-Z0-9._-] and starting with [a-zA-Z].
+bool NativeBridgeNameAcceptable(const char* nb_library_filename) {
+  const char* ptr = nb_library_filename;
+  if (*ptr == 0) {
+    // Emptry string. Allowed, means no native bridge.
+    return true;
+  } else {
+    // First character must be [a-zA-Z].
+    if (!CharacterAllowed(*ptr, true))  {
+      // Found an invalid fist character, don't accept.
+      ALOGE("Native bridge library %s has been rejected for first character %c", nb_library_filename, *ptr);
+      return false;
+    } else {
+      // For the rest, be more liberal.
+      ptr++;
+      while (*ptr != 0) {
+        if (!CharacterAllowed(*ptr, false)) {
+          // Found an invalid character, don't accept.
+          ALOGE("Native bridge library %s has been rejected for %c", nb_library_filename, *ptr);
+          return false;
+        }
+        ptr++;
+      }
+    }
+    return true;
+  }
+}
+
+static bool VersionCheck(NativeBridgeCallbacks* cb) {
+  return cb != nullptr && cb->version == kNativeBridgeCallbackVersion;
+}
+
+bool LoadNativeBridge(const char* nb_library_filename,
+                      const NativeBridgeRuntimeCallbacks* runtime_cbs) {
+  // We expect only one place that calls LoadNativeBridge: Runtime::Init. At that point we are not
+  // multi-threaded, so we do not need locking here.
+
+  if (state != NativeBridgeState::kNotSetup) {
+    // Setup has been called before. Ignore this call.
+    if (nb_library_filename != nullptr) {  // Avoids some log-spam for dalvikvm.
+      ALOGW("Called LoadNativeBridge for an already set up native bridge. State is %s.",
+            GetNativeBridgeStateString(state));
+    }
+    // Note: counts as an error, even though the bridge may be functional.
+    had_error = true;
+    return false;
+  }
+
+  if (nb_library_filename == nullptr || *nb_library_filename == 0) {
+    state = NativeBridgeState::kClosed;
+    return true;
+  } else {
+    if (!NativeBridgeNameAcceptable(nb_library_filename)) {
+      state = NativeBridgeState::kClosed;
+      had_error = true;
+    } else {
+      // Try to open the library.
+      void* handle = dlopen(nb_library_filename, RTLD_LAZY);
+      if (handle != nullptr) {
+        callbacks = reinterpret_cast<NativeBridgeCallbacks*>(dlsym(handle,
+                                                                   kNativeBridgeInterfaceSymbol));
+        if (callbacks != nullptr) {
+          if (VersionCheck(callbacks)) {
+            // Store the handle for later.
+            native_bridge_handle = handle;
+          } else {
+            callbacks = nullptr;
+            dlclose(handle);
+            ALOGW("Unsupported native bridge interface.");
+          }
+        } else {
+          dlclose(handle);
+        }
+      }
+
+      // Two failure conditions: could not find library (dlopen failed), or could not find native
+      // bridge interface (dlsym failed). Both are an error and close the native bridge.
+      if (callbacks == nullptr) {
+        had_error = true;
+        state = NativeBridgeState::kClosed;
+      } else {
+        runtime_callbacks = runtime_cbs;
+        state = NativeBridgeState::kOpened;
+      }
+    }
+    return state == NativeBridgeState::kOpened;
+  }
+}
+
+#if defined(__arm__)
+static const char* kRuntimeISA = "arm";
+#elif defined(__aarch64__)
+static const char* kRuntimeISA = "arm64";
+#elif defined(__mips__)
+static const char* kRuntimeISA = "mips";
+#elif defined(__i386__)
+static const char* kRuntimeISA = "x86";
+#elif defined(__x86_64__)
+static const char* kRuntimeISA = "x86_64";
+#else
+static const char* kRuntimeISA = "unknown";
+#endif
+
+
+bool NeedsNativeBridge(const char* instruction_set) {
+  if (instruction_set == nullptr) {
+    ALOGE("Null instruction set in NeedsNativeBridge.");
+    return false;
+  }
+  return strncmp(instruction_set, kRuntimeISA, strlen(kRuntimeISA) + 1) != 0;
+}
+
+#ifdef __APPLE__
+template<typename T> void UNUSED(const T&) {}
+#endif
+
+void PreInitializeNativeBridge(const char* app_data_dir_in, const char* instruction_set) {
+  if (app_data_dir_in == nullptr) {
+    return;
+  }
+
+  const size_t len = strlen(app_data_dir_in);
+  // Make a copy for us.
+  app_data_dir = new char[len];
+  strncpy(app_data_dir, app_data_dir_in, len);
+
+#ifndef __APPLE__
+  if (instruction_set == nullptr) {
+    return;
+  }
+  size_t isa_len = strlen(instruction_set);
+  if (isa_len > 10) {
+    // 10 is a loose upper bound on the currently known instruction sets (a tight bound is 7 for
+    // x86_64 [including the trailing \0]). This is so we don't have to change here if there will
+    // be another instruction set in the future.
+    ALOGW("Instruction set %s is malformed, must be less than or equal to 10 characters.",
+          instruction_set);
+    return;
+  }
+
+  // Bind-mount /system/lib{,64}/<isa>/cpuinfo to /proc/cpuinfo. If the file does not exist, the
+  // mount command will fail, so we safe the extra file existence check...
+  char cpuinfo_path[1024];
+
+#ifdef HAVE_ANDROID_OS
+  snprintf(cpuinfo_path, sizeof(cpuinfo_path), "/system/lib"
+#ifdef __LP64__
+      "64"
+#endif  // __LP64__
+      "/%s/cpuinfo", instruction_set);
+#else   // !HAVE_ANDROID_OS
+  // To be able to test on the host, we hardwire a relative path.
+  snprintf(cpuinfo_path, sizeof(cpuinfo_path), "./cpuinfo");
+#endif
+
+  // Bind-mount.
+  if (TEMP_FAILURE_RETRY(mount(cpuinfo_path,        // Source.
+                               "/proc/cpuinfo",     // Target.
+                               nullptr,             // FS type.
+                               MS_BIND,             // Mount flags: bind mount.
+                               nullptr)) == -1) {   // "Data."
+    ALOGW("Failed to bind-mount %s as /proc/cpuinfo: %s", cpuinfo_path, strerror(errno));
+  }
+#else
+  UNUSED(instruction_set);
+  ALOGW("Mac OS does not support bind-mounting. Host simulation of native bridge impossible.");
+#endif
+}
+
+static void SetCpuAbi(JNIEnv* env, jclass build_class, const char* field, const char* value) {
+  if (value != nullptr) {
+    jfieldID field_id = env->GetStaticFieldID(build_class, field, "Ljava/lang/String;");
+    if (field_id == nullptr) {
+      env->ExceptionClear();
+      ALOGW("Could not find %s field.", field);
+      return;
+    }
+
+    jstring str = env->NewStringUTF(value);
+    if (str == nullptr) {
+      env->ExceptionClear();
+      ALOGW("Could not create string %s.", value);
+      return;
+    }
+
+    env->SetStaticObjectField(build_class, field_id, str);
+  }
+}
+
+// Set up the environment for the bridged app.
+static void SetupEnvironment(NativeBridgeCallbacks* callbacks, JNIEnv* env, const char* isa) {
+  // Need a JNIEnv* to do anything.
+  if (env == nullptr) {
+    ALOGW("No JNIEnv* to set up app environment.");
+    return;
+  }
+
+  // Query the bridge for environment values.
+  const struct NativeBridgeRuntimeValues* env_values = callbacks->getAppEnv(isa);
+  if (env_values == nullptr) {
+    return;
+  }
+
+  // Keep the JNIEnv clean.
+  jint success = env->PushLocalFrame(16);  // That should be small and large enough.
+  if (success < 0) {
+    // Out of memory, really borked.
+    ALOGW("Out of memory while setting up app environment.");
+    env->ExceptionClear();
+    return;
+  }
+
+  // Reset CPU_ABI & CPU_ABI2 to values required by the apps running with native bridge.
+  if (env_values->cpu_abi != nullptr || env_values->cpu_abi2 != nullptr ||
+      env_values->abi_count >= 0) {
+    jclass bclass_id = env->FindClass("android/os/Build");
+    if (bclass_id != nullptr) {
+      SetCpuAbi(env, bclass_id, "CPU_ABI", env_values->cpu_abi);
+      SetCpuAbi(env, bclass_id, "CPU_ABI2", env_values->cpu_abi2);
+    } else {
+      // For example in a host test environment.
+      env->ExceptionClear();
+      ALOGW("Could not find Build class.");
+    }
+  }
+
+  if (env_values->os_arch != nullptr) {
+    jclass sclass_id = env->FindClass("java/lang/System");
+    if (sclass_id != nullptr) {
+      jmethodID set_prop_id = env->GetStaticMethodID(sclass_id, "initUnchangeableSystemProperty",
+          "(Ljava/lang/String;Ljava/lang/String;)V");
+      if (set_prop_id != nullptr) {
+        // Init os.arch to the value reqired by the apps running with native bridge.
+        env->CallStaticVoidMethod(sclass_id, set_prop_id, env->NewStringUTF("os.arch"),
+            env->NewStringUTF(env_values->os_arch));
+      } else {
+        env->ExceptionClear();
+        ALOGW("Could not find initUnchangeableSystemProperty method.");
+      }
+    } else {
+      env->ExceptionClear();
+      ALOGW("Could not find System class.");
+    }
+  }
+
+  // Make it pristine again.
+  env->PopLocalFrame(nullptr);
+}
+
+bool InitializeNativeBridge(JNIEnv* env, const char* instruction_set) {
+  // We expect only one place that calls InitializeNativeBridge: Runtime::DidForkFromZygote. At that
+  // point we are not multi-threaded, so we do not need locking here.
+
+  if (state == NativeBridgeState::kOpened) {
+    // Try to initialize.
+    if (callbacks->initialize(runtime_callbacks, app_data_dir, instruction_set)) {
+      SetupEnvironment(callbacks, env, instruction_set);
+      state = NativeBridgeState::kInitialized;
+    } else {
+      // Unload the library.
+      dlclose(native_bridge_handle);
+      had_error = true;
+      state = NativeBridgeState::kClosed;
+    }
+  } else {
+    had_error = true;
+    state = NativeBridgeState::kClosed;
+  }
+
+  return state == NativeBridgeState::kInitialized;
+}
+
+void UnloadNativeBridge() {
+  // We expect only one place that calls UnloadNativeBridge: Runtime::DidForkFromZygote. At that
+  // point we are not multi-threaded, so we do not need locking here.
+
+  switch(state) {
+    case NativeBridgeState::kOpened:
+    case NativeBridgeState::kInitialized:
+      // Unload.
+      dlclose(native_bridge_handle);
+      break;
+
+    case NativeBridgeState::kNotSetup:
+      // Not even set up. Error.
+      had_error = true;
+      break;
+
+    case NativeBridgeState::kClosed:
+      // Ignore.
+      break;
+  }
+
+  state = NativeBridgeState::kClosed;
+}
+
+bool NativeBridgeError() {
+  return had_error;
+}
+
+bool NativeBridgeAvailable() {
+  return state == NativeBridgeState::kOpened || state == NativeBridgeState::kInitialized;
+}
+
+bool NativeBridgeInitialized() {
+  // Calls of this are supposed to happen in a state where the native bridge is stable, i.e., after
+  // Runtime::DidForkFromZygote. In that case we do not need a lock.
+  return state == NativeBridgeState::kInitialized;
+}
+
+void* NativeBridgeLoadLibrary(const char* libpath, int flag) {
+  if (NativeBridgeInitialized()) {
+    return callbacks->loadLibrary(libpath, flag);
+  }
+  return nullptr;
+}
+
+void* NativeBridgeGetTrampoline(void* handle, const char* name, const char* shorty,
+                                uint32_t len) {
+  if (NativeBridgeInitialized()) {
+    return callbacks->getTrampoline(handle, name, shorty, len);
+  }
+  return nullptr;
+}
+
+bool NativeBridgeIsSupported(const char* libpath) {
+  if (NativeBridgeInitialized()) {
+    return callbacks->isSupported(libpath);
+  }
+  return false;
+}
+
+};  // namespace android
diff --git a/libnativebridge/tests/Android.mk b/libnativebridge/tests/Android.mk
new file mode 100644
index 0000000..9c7e1b8
--- /dev/null
+++ b/libnativebridge/tests/Android.mk
@@ -0,0 +1,36 @@
+# Build the unit tests.
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+# Build the unit tests.
+test_src_files := \
+    InvalidCharsNativeBridge_test.cpp \
+    NeedsNativeBridge_test.cpp \
+    PreInitializeNativeBridge_test.cpp \
+    ReSetupNativeBridge_test.cpp \
+    UnavailableNativeBridge_test.cpp \
+    ValidNameNativeBridge_test.cpp
+
+shared_libraries := \
+    liblog \
+    libnativebridge
+
+$(foreach file,$(test_src_files), \
+    $(eval include $(CLEAR_VARS)) \
+    $(eval LOCAL_CLANG := true) \
+    $(eval LOCAL_CPPFLAGS := -std=gnu++11) \
+    $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
+    $(eval LOCAL_SRC_FILES := $(file)) \
+    $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
+    $(eval include $(BUILD_NATIVE_TEST)) \
+)
+
+$(foreach file,$(test_src_files), \
+    $(eval include $(CLEAR_VARS)) \
+    $(eval LOCAL_CLANG := true) \
+    $(eval LOCAL_CPPFLAGS := -std=gnu++11) \
+    $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
+    $(eval LOCAL_SRC_FILES := $(file)) \
+    $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
+    $(eval include $(BUILD_HOST_NATIVE_TEST)) \
+)
\ No newline at end of file
diff --git a/libnativebridge/tests/InvalidCharsNativeBridge_test.cpp b/libnativebridge/tests/InvalidCharsNativeBridge_test.cpp
new file mode 100644
index 0000000..8f7973d
--- /dev/null
+++ b/libnativebridge/tests/InvalidCharsNativeBridge_test.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2014 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 "NativeBridgeTest.h"
+
+namespace android {
+
+static const char* kTestName = "../librandom$@-bridge_not.existing.so";
+
+TEST_F(NativeBridgeTest, InvalidChars) {
+    // Do one test actually calling setup.
+    EXPECT_EQ(false, NativeBridgeError());
+    LoadNativeBridge(kTestName, nullptr);
+    // This should lead to an error for invalid characters.
+    EXPECT_EQ(true, NativeBridgeError());
+
+    // Further tests need to use NativeBridgeNameAcceptable, as the error
+    // state can't be changed back.
+    EXPECT_EQ(false, NativeBridgeNameAcceptable("."));
+    EXPECT_EQ(false, NativeBridgeNameAcceptable(".."));
+    EXPECT_EQ(false, NativeBridgeNameAcceptable("_"));
+    EXPECT_EQ(false, NativeBridgeNameAcceptable("-"));
+    EXPECT_EQ(false, NativeBridgeNameAcceptable("lib@.so"));
+    EXPECT_EQ(false, NativeBridgeNameAcceptable("lib$.so"));
+}
+
+}  // namespace android
diff --git a/include/cutils/tztime.h b/libnativebridge/tests/NativeBridgeTest.h
similarity index 61%
rename from include/cutils/tztime.h
rename to libnativebridge/tests/NativeBridgeTest.h
index dbdbd60..0d731cb 100644
--- a/include/cutils/tztime.h
+++ b/libnativebridge/tests/NativeBridgeTest.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006 The Android Open Source Project
+ * Copyright (C) 2014 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.
@@ -14,11 +14,20 @@
  * limitations under the License.
  */
 
-#ifndef _CUTILS_TZTIME_H
-#define _CUTILS_TZTIME_H
+#ifndef NATIVE_BRIDGE_TEST_H_
+#define NATIVE_BRIDGE_TEST_H_
 
-// TODO: fix both callers to just include <bionic_time.h> themselves.
-#include <bionic_time.h>
+#define LOG_TAG "NativeBridge_test"
 
-#endif /* __CUTILS_TZTIME_H */ 
+#include <nativebridge/native_bridge.h>
+#include <gtest/gtest.h>
+
+namespace android {
+
+class NativeBridgeTest : public testing::Test {
+};
+
+};  // namespace android
+
+#endif  // NATIVE_BRIDGE_H_
 
diff --git a/libnativebridge/tests/NeedsNativeBridge_test.cpp b/libnativebridge/tests/NeedsNativeBridge_test.cpp
new file mode 100644
index 0000000..e1c0876
--- /dev/null
+++ b/libnativebridge/tests/NeedsNativeBridge_test.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2014 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 "NativeBridgeTest.h"
+
+namespace android {
+
+static const char* kISAs[] = { "arm", "arm64", "mips", "x86", "x86_64", "random", "64arm", "64_x86",
+                               "64_x86_64", "", "reallylongstringabcd", nullptr };
+
+#if defined(__arm__)
+static const char* kRuntimeISA = "arm";
+#elif defined(__aarch64__)
+static const char* kRuntimeISA = "arm64";
+#elif defined(__mips__)
+static const char* kRuntimeISA = "mips";
+#elif defined(__i386__)
+static const char* kRuntimeISA = "x86";
+#elif defined(__x86_64__)
+static const char* kRuntimeISA = "x86_64";
+#else
+static const char* kRuntimeISA = "unknown";
+#endif
+
+TEST_F(NativeBridgeTest, NeedsNativeBridge) {
+    EXPECT_EQ(false, NeedsNativeBridge(kRuntimeISA));
+
+    const size_t kISACount = sizeof(kISAs)/sizeof(kISAs[0]);
+    for (size_t i = 0; i < kISACount; i++) {
+        EXPECT_EQ(kISAs[i] == nullptr ? false : strcmp(kISAs[i], kRuntimeISA) != 0,
+                  NeedsNativeBridge(kISAs[i]));
+    }
+}
+
+}  // namespace android
diff --git a/libnativebridge/tests/PreInitializeNativeBridge_test.cpp b/libnativebridge/tests/PreInitializeNativeBridge_test.cpp
new file mode 100644
index 0000000..84078f7
--- /dev/null
+++ b/libnativebridge/tests/PreInitializeNativeBridge_test.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2014 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 "NativeBridgeTest.h"
+
+#include <cstdio>
+#include <cstring>
+#include <cutils/log.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+
+namespace android {
+
+static constexpr const char* kTestData = "PreInitializeNativeBridge test.";
+
+TEST_F(NativeBridgeTest, PreInitializeNativeBridge) {
+#ifndef __APPLE__         // Mac OS does not support bind-mount.
+#ifndef HAVE_ANDROID_OS   // Cannot write into the hard-wired location.
+    // Try to create our mount namespace.
+    if (unshare(CLONE_NEWNS) != -1) {
+        // Create a dummy file.
+        FILE* cpuinfo = fopen("./cpuinfo", "w");
+        ASSERT_NE(nullptr, cpuinfo) << strerror(errno);
+        fprintf(cpuinfo, kTestData);
+        fclose(cpuinfo);
+
+        // Call the setup.
+        PreInitializeNativeBridge("does not matter 1", "short 2");
+
+        // Read /proc/cpuinfo
+        FILE* proc_cpuinfo = fopen("/proc/cpuinfo", "r");
+        ASSERT_NE(nullptr, proc_cpuinfo) << strerror(errno);
+        char buf[1024];
+        EXPECT_NE(nullptr, fgets(buf, sizeof(buf), proc_cpuinfo)) << "Error reading.";
+        fclose(proc_cpuinfo);
+
+        EXPECT_EQ(0, strcmp(buf, kTestData));
+
+        // Delete the file.
+        ASSERT_EQ(0, unlink("./cpuinfo")) << "Error unlinking temporary file.";
+        // Ending the test will tear down the mount namespace.
+    } else {
+        GTEST_LOG_(WARNING) << "Could not create mount namespace. Are you running this as root?";
+    }
+#endif
+#endif
+}
+
+}  // namespace android
diff --git a/libnativebridge/tests/ReSetupNativeBridge_test.cpp b/libnativebridge/tests/ReSetupNativeBridge_test.cpp
new file mode 100644
index 0000000..944e5d7
--- /dev/null
+++ b/libnativebridge/tests/ReSetupNativeBridge_test.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2014 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 "NativeBridgeTest.h"
+
+namespace android {
+
+TEST_F(NativeBridgeTest, ReSetup) {
+    EXPECT_EQ(false, NativeBridgeError());
+    LoadNativeBridge("", nullptr);
+    EXPECT_EQ(false, NativeBridgeError());
+    LoadNativeBridge("", nullptr);
+    // This should lead to an error for trying to re-setup a native bridge.
+    EXPECT_EQ(true, NativeBridgeError());
+}
+
+}  // namespace android
diff --git a/libnativebridge/tests/UnavailableNativeBridge_test.cpp b/libnativebridge/tests/UnavailableNativeBridge_test.cpp
new file mode 100644
index 0000000..ad374a5
--- /dev/null
+++ b/libnativebridge/tests/UnavailableNativeBridge_test.cpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2011 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 "NativeBridgeTest.h"
+
+namespace android {
+
+TEST_F(NativeBridgeTest, NoNativeBridge) {
+    EXPECT_EQ(false, NativeBridgeAvailable());
+    // Try to initialize. This should fail as we are not set up.
+    EXPECT_EQ(false, InitializeNativeBridge(nullptr, nullptr));
+    EXPECT_EQ(true, NativeBridgeError());
+    EXPECT_EQ(false, NativeBridgeAvailable());
+}
+
+}  // namespace android
diff --git a/libnativebridge/tests/ValidNameNativeBridge_test.cpp b/libnativebridge/tests/ValidNameNativeBridge_test.cpp
new file mode 100644
index 0000000..690be4a
--- /dev/null
+++ b/libnativebridge/tests/ValidNameNativeBridge_test.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2011 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 <NativeBridgeTest.h>
+
+namespace android {
+
+static const char* kTestName = "librandom-bridge_not.existing.so";
+
+TEST_F(NativeBridgeTest, ValidName) {
+    // Check that the name is acceptable.
+    EXPECT_EQ(true, NativeBridgeNameAcceptable(kTestName));
+
+    // Now check what happens on LoadNativeBridge.
+    EXPECT_EQ(false, NativeBridgeError());
+    LoadNativeBridge(kTestName, nullptr);
+    // This will lead to an error as the library doesn't exist.
+    EXPECT_EQ(true, NativeBridgeError());
+    EXPECT_EQ(false, NativeBridgeAvailable());
+}
+
+}  // namespace android
diff --git a/libnetutils/ifc_utils.c b/libnetutils/ifc_utils.c
index 4d004f6..913f51e 100644
--- a/libnetutils/ifc_utils.c
+++ b/libnetutils/ifc_utils.c
@@ -563,17 +563,7 @@
     return ret;
 }
 
-/* deprecated v4-only */
-int ifc_add_host_route(const char *name, in_addr_t dst)
-{
-    struct in_addr in_dst, in_gw;
-
-    in_dst.s_addr = dst;
-    in_gw.s_addr = 0;
-
-    return ifc_act_on_ipv4_route(SIOCADDRT, name, in_dst, 32, in_gw);
-}
-
+// Needed by code in hidden partner repositories / branches, so don't delete.
 int ifc_enable(const char *ifname)
 {
     int result;
@@ -584,6 +574,7 @@
     return result;
 }
 
+// Needed by code in hidden partner repositories / branches, so don't delete.
 int ifc_disable(const char *ifname)
 {
     unsigned addr, count;
@@ -608,14 +599,16 @@
 {
 #ifdef HAVE_ANDROID_OS
     int result, success;
-    in_addr_t myaddr;
+    in_addr_t myaddr = 0;
     struct ifreq ifr;
     struct in6_ifreq ifr6;
 
     if (reset_mask & RESET_IPV4_ADDRESSES) {
         /* IPv4. Clear connections on the IP address. */
         ifc_init();
-        ifc_get_info(ifname, &myaddr, NULL, NULL);
+        if (!(reset_mask & RESET_IGNORE_INTERFACE_ADDRESS)) {
+            ifc_get_info(ifname, &myaddr, NULL, NULL);
+        }
         ifc_init_ifr(ifname, &ifr);
         init_sockaddr_in(&ifr.ifr_addr, myaddr);
         result = ioctl(ifc_ctl_sock, SIOCKILLADDR,  &ifr);
@@ -648,118 +641,6 @@
 }
 
 /*
- * Remove the routes associated with the named interface.
- */
-int ifc_remove_host_routes(const char *name)
-{
-    char ifname[64];
-    in_addr_t dest, gway, mask;
-    int flags, refcnt, use, metric, mtu, win, irtt;
-    struct rtentry rt;
-    FILE *fp;
-    struct in_addr addr;
-
-    fp = fopen("/proc/net/route", "r");
-    if (fp == NULL)
-        return -1;
-    /* Skip the header line */
-    if (fscanf(fp, "%*[^\n]\n") < 0) {
-        fclose(fp);
-        return -1;
-    }
-    ifc_init();
-    for (;;) {
-        int nread = fscanf(fp, "%63s%X%X%X%d%d%d%X%d%d%d\n",
-                           ifname, &dest, &gway, &flags, &refcnt, &use, &metric, &mask,
-                           &mtu, &win, &irtt);
-        if (nread != 11) {
-            break;
-        }
-        if ((flags & (RTF_UP|RTF_HOST)) != (RTF_UP|RTF_HOST)
-                || strcmp(ifname, name) != 0) {
-            continue;
-        }
-        memset(&rt, 0, sizeof(rt));
-        rt.rt_dev = (void *)name;
-        init_sockaddr_in(&rt.rt_dst, dest);
-        init_sockaddr_in(&rt.rt_gateway, gway);
-        init_sockaddr_in(&rt.rt_genmask, mask);
-        addr.s_addr = dest;
-        if (ioctl(ifc_ctl_sock, SIOCDELRT, &rt) < 0) {
-            ALOGD("failed to remove route for %s to %s: %s",
-                 ifname, inet_ntoa(addr), strerror(errno));
-        }
-    }
-    fclose(fp);
-    ifc_close();
-    return 0;
-}
-
-/*
- * Return the address of the default gateway
- *
- * TODO: factor out common code from this and remove_host_routes()
- * so that we only scan /proc/net/route in one place.
- *
- * DEPRECATED
- */
-int ifc_get_default_route(const char *ifname)
-{
-    char name[64];
-    in_addr_t dest, gway, mask;
-    int flags, refcnt, use, metric, mtu, win, irtt;
-    int result;
-    FILE *fp;
-
-    fp = fopen("/proc/net/route", "r");
-    if (fp == NULL)
-        return 0;
-    /* Skip the header line */
-    if (fscanf(fp, "%*[^\n]\n") < 0) {
-        fclose(fp);
-        return 0;
-    }
-    ifc_init();
-    result = 0;
-    for (;;) {
-        int nread = fscanf(fp, "%63s%X%X%X%d%d%d%X%d%d%d\n",
-                           name, &dest, &gway, &flags, &refcnt, &use, &metric, &mask,
-                           &mtu, &win, &irtt);
-        if (nread != 11) {
-            break;
-        }
-        if ((flags & (RTF_UP|RTF_GATEWAY)) == (RTF_UP|RTF_GATEWAY)
-                && dest == 0
-                && strcmp(ifname, name) == 0) {
-            result = gway;
-            break;
-        }
-    }
-    fclose(fp);
-    ifc_close();
-    return result;
-}
-
-/*
- * Sets the specified gateway as the default route for the named interface.
- * DEPRECATED
- */
-int ifc_set_default_route(const char *ifname, in_addr_t gateway)
-{
-    struct in_addr addr;
-    int result;
-
-    ifc_init();
-    addr.s_addr = gateway;
-    if ((result = ifc_create_default_route(ifname, gateway)) < 0) {
-        ALOGD("failed to add %s as default route for %s: %s",
-             inet_ntoa(addr), ifname, strerror(errno));
-    }
-    ifc_close();
-    return result;
-}
-
-/*
  * Removes the default route for the named interface.
  */
 int ifc_remove_default_route(const char *ifname)
@@ -821,151 +702,3 @@
 
     return 0;
 }
-
-int ifc_act_on_ipv6_route(int action, const char *ifname, struct in6_addr dst, int prefix_length,
-      struct in6_addr gw)
-{
-    struct in6_rtmsg rtmsg;
-    int result;
-    int ifindex;
-
-    memset(&rtmsg, 0, sizeof(rtmsg));
-
-    ifindex = if_nametoindex(ifname);
-    if (ifindex == 0) {
-        printerr("if_nametoindex() failed: interface %s\n", ifname);
-        return -ENXIO;
-    }
-
-    rtmsg.rtmsg_ifindex = ifindex;
-    rtmsg.rtmsg_dst = dst;
-    rtmsg.rtmsg_dst_len = prefix_length;
-    rtmsg.rtmsg_flags = RTF_UP;
-
-    if (prefix_length == 128) {
-        rtmsg.rtmsg_flags |= RTF_HOST;
-    }
-
-    if (memcmp(&gw, &in6addr_any, sizeof(in6addr_any))) {
-        rtmsg.rtmsg_flags |= RTF_GATEWAY;
-        rtmsg.rtmsg_gateway = gw;
-    }
-
-    ifc_init6();
-
-    if (ifc_ctl_sock6 < 0) {
-        return -errno;
-    }
-
-    result = ioctl(ifc_ctl_sock6, action, &rtmsg);
-    if (result < 0) {
-        if (errno == EEXIST) {
-            result = 0;
-        } else {
-            result = -errno;
-        }
-    }
-    ifc_close6();
-    return result;
-}
-
-int ifc_act_on_route(int action, const char *ifname, const char *dst, int prefix_length,
-        const char *gw)
-{
-    int ret = 0;
-    struct sockaddr_in ipv4_dst, ipv4_gw;
-    struct sockaddr_in6 ipv6_dst, ipv6_gw;
-    struct addrinfo hints, *addr_ai, *gw_ai;
-
-    memset(&hints, 0, sizeof(hints));
-    hints.ai_family = AF_UNSPEC;  /* Allow IPv4 or IPv6 */
-    hints.ai_flags = AI_NUMERICHOST;
-
-    ret = getaddrinfo(dst, NULL, &hints, &addr_ai);
-
-    if (ret != 0) {
-        printerr("getaddrinfo failed: invalid address %s\n", dst);
-        return -EINVAL;
-    }
-
-    if (gw == NULL || (strlen(gw) == 0)) {
-        if (addr_ai->ai_family == AF_INET6) {
-            gw = "::";
-        } else if (addr_ai->ai_family == AF_INET) {
-            gw = "0.0.0.0";
-        }
-    }
-
-    if (((addr_ai->ai_family == AF_INET6) && (prefix_length < 0 || prefix_length > 128)) ||
-            ((addr_ai->ai_family == AF_INET) && (prefix_length < 0 || prefix_length > 32))) {
-        printerr("ifc_add_route: invalid prefix length");
-        freeaddrinfo(addr_ai);
-        return -EINVAL;
-    }
-
-    ret = getaddrinfo(gw, NULL, &hints, &gw_ai);
-    if (ret != 0) {
-        printerr("getaddrinfo failed: invalid gateway %s\n", gw);
-        freeaddrinfo(addr_ai);
-        return -EINVAL;
-    }
-
-    if (addr_ai->ai_family != gw_ai->ai_family) {
-        printerr("ifc_add_route: different address families: %s and %s\n", dst, gw);
-        freeaddrinfo(addr_ai);
-        freeaddrinfo(gw_ai);
-        return -EINVAL;
-    }
-
-    if (addr_ai->ai_family == AF_INET6) {
-        memcpy(&ipv6_dst, addr_ai->ai_addr, sizeof(struct sockaddr_in6));
-        memcpy(&ipv6_gw, gw_ai->ai_addr, sizeof(struct sockaddr_in6));
-        ret = ifc_act_on_ipv6_route(action, ifname, ipv6_dst.sin6_addr,
-                prefix_length, ipv6_gw.sin6_addr);
-    } else if (addr_ai->ai_family == AF_INET) {
-        memcpy(&ipv4_dst, addr_ai->ai_addr, sizeof(struct sockaddr_in));
-        memcpy(&ipv4_gw, gw_ai->ai_addr, sizeof(struct sockaddr_in));
-        ret = ifc_act_on_ipv4_route(action, ifname, ipv4_dst.sin_addr,
-                prefix_length, ipv4_gw.sin_addr);
-    } else {
-        printerr("ifc_add_route: getaddrinfo returned un supported address family %d\n",
-                  addr_ai->ai_family);
-        ret = -EAFNOSUPPORT;
-    }
-
-    freeaddrinfo(addr_ai);
-    freeaddrinfo(gw_ai);
-    return ret;
-}
-
-/*
- * DEPRECATED
- */
-int ifc_add_ipv4_route(const char *ifname, struct in_addr dst, int prefix_length,
-      struct in_addr gw)
-{
-    int i =ifc_act_on_ipv4_route(SIOCADDRT, ifname, dst, prefix_length, gw);
-    if (DBG) printerr("ifc_add_ipv4_route(%s, xx, %d, xx) = %d", ifname, prefix_length, i);
-    return i;
-}
-
-/*
- * DEPRECATED
- */
-int ifc_add_ipv6_route(const char *ifname, struct in6_addr dst, int prefix_length,
-      struct in6_addr gw)
-{
-    return ifc_act_on_ipv6_route(SIOCADDRT, ifname, dst, prefix_length, gw);
-}
-
-int ifc_add_route(const char *ifname, const char *dst, int prefix_length, const char *gw)
-{
-    int i = ifc_act_on_route(SIOCADDRT, ifname, dst, prefix_length, gw);
-    if (DBG) printerr("ifc_add_route(%s, %s, %d, %s) = %d", ifname, dst, prefix_length, gw, i);
-    return i;
-}
-
-int ifc_remove_route(const char *ifname, const char*dst, int prefix_length, const char *gw)
-{
-    return ifc_act_on_route(SIOCDELRT, ifname, dst, prefix_length, gw);
-}
diff --git a/libnetutils/packet.c b/libnetutils/packet.c
index be4e0db..3cdefb0 100644
--- a/libnetutils/packet.c
+++ b/libnetutils/packet.c
@@ -230,6 +230,8 @@
     packet.udp.check = 0;
     sum = finish_sum(checksum(&packet, nread, 0));
     packet.udp.check = temp;
+    if (!sum)
+        sum = finish_sum(sum);
     if (temp != sum) {
         ALOGW("UDP header checksum failure (0x%x should be 0x%x)", sum, temp);
         return -1;
diff --git a/libprocessgroup/Android.mk b/libprocessgroup/Android.mk
new file mode 100644
index 0000000..051999a
--- /dev/null
+++ b/libprocessgroup/Android.mk
@@ -0,0 +1,21 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := processgroup.cpp
+LOCAL_MODULE := libprocessgroup
+LOCAL_SHARED_LIBRARIES := liblog libutils
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_CFLAGS := -Wall -Werror
+LOCAL_REQUIRED_MODULE := processgroup_cleanup
+include external/libcxx/libcxx.mk
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := cleanup.cpp
+LOCAL_MODULE := processgroup_cleanup
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_CFLAGS := -Wall -Werror
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_STATIC_LIBRARIES := libc libcutils
+include $(BUILD_EXECUTABLE)
diff --git a/libprocessgroup/cleanup.cpp b/libprocessgroup/cleanup.cpp
new file mode 100644
index 0000000..cca8dc4
--- /dev/null
+++ b/libprocessgroup/cleanup.cpp
@@ -0,0 +1,31 @@
+/*
+ *  Copyright 2014 Google, Inc
+ *
+ *  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 <unistd.h>
+#include <sys/syslimits.h>
+
+#include "processgroup_priv.h"
+
+int main(int argc, char **argv)
+{
+    char buf[PATH_MAX];
+    if (argc != 2)
+        return -1;
+
+    memcpy(buf, PROCESSGROUP_CGROUP_PATH, sizeof(PROCESSGROUP_CGROUP_PATH));
+    strlcat(buf, argv[1], sizeof(buf));
+    return rmdir(buf);
+}
diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h
new file mode 100644
index 0000000..11bd8cc
--- /dev/null
+++ b/libprocessgroup/include/processgroup/processgroup.h
@@ -0,0 +1,33 @@
+/*
+ *  Copyright 2014 Google, Inc
+ *
+ *  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 _PROCESSGROUP_H_
+#define _PROCESSGROUP_H_
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+__BEGIN_DECLS
+
+int killProcessGroup(uid_t uid, int initialPid, int signal);
+
+int createProcessGroup(uid_t uid, int initialPid);
+
+void removeAllProcessGroups(void);
+
+__END_DECLS
+
+#endif
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
new file mode 100644
index 0000000..49f5903
--- /dev/null
+++ b/libprocessgroup/processgroup.cpp
@@ -0,0 +1,341 @@
+/*
+ *  Copyright 2014 Google, Inc
+ *
+ *  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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "libprocessgroup"
+
+#include <assert.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <log/log.h>
+#include <private/android_filesystem_config.h>
+
+#include <utils/SystemClock.h>
+
+#include <processgroup/processgroup.h>
+#include "processgroup_priv.h"
+
+struct ctx {
+    bool initialized;
+    int fd;
+    char buf[128];
+    char *buf_ptr;
+    size_t buf_len;
+};
+
+static int convertUidToPath(char *path, size_t size, uid_t uid)
+{
+    return snprintf(path, size, "%s/%s%d",
+            PROCESSGROUP_CGROUP_PATH,
+            PROCESSGROUP_UID_PREFIX,
+            uid);
+}
+
+static int convertUidPidToPath(char *path, size_t size, uid_t uid, int pid)
+{
+    return snprintf(path, size, "%s/%s%d/%s%d",
+            PROCESSGROUP_CGROUP_PATH,
+            PROCESSGROUP_UID_PREFIX,
+            uid,
+            PROCESSGROUP_PID_PREFIX,
+            pid);
+}
+
+static int initCtx(uid_t uid, int pid, struct ctx *ctx)
+{
+    int ret;
+    char path[PROCESSGROUP_MAX_PATH_LEN] = {0};
+    convertUidPidToPath(path, sizeof(path), uid, pid);
+    strlcat(path, PROCESSGROUP_CGROUP_PROCS_FILE, sizeof(path));
+
+    int fd = open(path, O_RDONLY);
+    if (fd < 0) {
+        ret = -errno;
+        SLOGW("failed to open %s: %s", path, strerror(errno));
+        return ret;
+    }
+
+    ctx->fd = fd;
+    ctx->buf_ptr = ctx->buf;
+    ctx->buf_len = 0;
+    ctx->initialized = true;
+
+    SLOGV("Initialized context for %s", path);
+
+    return 0;
+}
+
+static int refillBuffer(struct ctx *ctx)
+{
+    memmove(ctx->buf, ctx->buf_ptr, ctx->buf_len);
+    ctx->buf_ptr = ctx->buf;
+
+    ssize_t ret = read(ctx->fd, ctx->buf_ptr + ctx->buf_len,
+                sizeof(ctx->buf) - ctx->buf_len - 1);
+    if (ret < 0) {
+        return -errno;
+    } else if (ret == 0) {
+        return 0;
+    }
+
+    ctx->buf_len += ret;
+    ctx->buf[ctx->buf_len] = 0;
+    SLOGV("Read %d to buffer: %s", ret, ctx->buf);
+
+    assert(ctx->buf_len <= sizeof(ctx->buf));
+
+    return ret;
+}
+
+static pid_t getOneAppProcess(uid_t uid, int appProcessPid, struct ctx *ctx)
+{
+    if (!ctx->initialized) {
+        int ret = initCtx(uid, appProcessPid, ctx);
+        if (ret < 0) {
+            return ret;
+        }
+    }
+
+    char *eptr;
+    while ((eptr = (char *)memchr(ctx->buf_ptr, '\n', ctx->buf_len)) == NULL) {
+        int ret = refillBuffer(ctx);
+        if (ret == 0) {
+            return -ERANGE;
+        }
+        if (ret < 0) {
+            return ret;
+        }
+    }
+
+    *eptr = '\0';
+    char *pid_eptr = NULL;
+    errno = 0;
+    long pid = strtol(ctx->buf_ptr, &pid_eptr, 10);
+    if (errno != 0) {
+        return -errno;
+    }
+    if (pid_eptr != eptr) {
+        return -EINVAL;
+    }
+
+    ctx->buf_len -= (eptr - ctx->buf_ptr) + 1;
+    ctx->buf_ptr = eptr + 1;
+
+    return (pid_t)pid;
+}
+
+static int removeProcessGroup(uid_t uid, int pid)
+{
+    int ret;
+    char path[PROCESSGROUP_MAX_PATH_LEN] = {0};
+
+    convertUidPidToPath(path, sizeof(path), uid, pid);
+    ret = rmdir(path);
+
+    convertUidToPath(path, sizeof(path), uid);
+    rmdir(path);
+
+    return ret;
+}
+
+static void removeUidProcessGroups(const char *uid_path)
+{
+    DIR *uid = opendir(uid_path);
+    if (uid != NULL) {
+        struct dirent cur;
+        struct dirent *dir;
+        while ((readdir_r(uid, &cur, &dir) == 0) && dir) {
+            char path[PROCESSGROUP_MAX_PATH_LEN];
+
+            if (dir->d_type != DT_DIR) {
+                continue;
+            }
+
+            if (strncmp(dir->d_name, PROCESSGROUP_PID_PREFIX, strlen(PROCESSGROUP_PID_PREFIX))) {
+                continue;
+            }
+
+            snprintf(path, sizeof(path), "%s/%s", uid_path, dir->d_name);
+            SLOGV("removing %s\n", path);
+            rmdir(path);
+        }
+        closedir(uid);
+    }
+}
+
+void removeAllProcessGroups()
+{
+    SLOGV("removeAllProcessGroups()");
+    DIR *root = opendir(PROCESSGROUP_CGROUP_PATH);
+    if (root == NULL) {
+        SLOGE("failed to open %s: %s", PROCESSGROUP_CGROUP_PATH, strerror(errno));
+    } else {
+        struct dirent cur;
+        struct dirent *dir;
+        while ((readdir_r(root, &cur, &dir) == 0) && dir) {
+            char path[PROCESSGROUP_MAX_PATH_LEN];
+
+            if (dir->d_type != DT_DIR) {
+                continue;
+            }
+            if (strncmp(dir->d_name, PROCESSGROUP_UID_PREFIX, strlen(PROCESSGROUP_UID_PREFIX))) {
+                continue;
+            }
+
+            snprintf(path, sizeof(path), "%s/%s", PROCESSGROUP_CGROUP_PATH, dir->d_name);
+            removeUidProcessGroups(path);
+            SLOGV("removing %s\n", path);
+            rmdir(path);
+        }
+        closedir(root);
+    }
+}
+
+static int killProcessGroupOnce(uid_t uid, int initialPid, int signal)
+{
+    int processes = 0;
+    struct ctx ctx;
+    pid_t pid;
+
+    ctx.initialized = false;
+
+    while ((pid = getOneAppProcess(uid, initialPid, &ctx)) >= 0) {
+        processes++;
+        if (pid == 0) {
+            // Should never happen...  but if it does, trying to kill this
+            // will boomerang right back and kill us!  Let's not let that happen.
+            SLOGW("Yikes, we've been told to kill pid 0!  How about we don't do that.");
+            continue;
+        }
+        if (pid != initialPid) {
+            // We want to be noisy about killing processes so we can understand
+            // what is going on in the log; however, don't be noisy about the base
+            // process, since that it something we always kill, and we have already
+            // logged elsewhere about killing it.
+            SLOGI("Killing pid %d in uid %d as part of process group %d", pid, uid, initialPid);
+        }
+        int ret = kill(pid, signal);
+        if (ret == -1) {
+            SLOGW("failed to kill pid %d: %s", pid, strerror(errno));
+        }
+    }
+
+    if (ctx.initialized) {
+        close(ctx.fd);
+    }
+
+    return processes;
+}
+
+int killProcessGroup(uid_t uid, int initialPid, int signal)
+{
+    int processes;
+    int sleep_us = 100;
+    long startTime = android::uptimeMillis();
+
+    while ((processes = killProcessGroupOnce(uid, initialPid, signal)) > 0) {
+        SLOGV("killed %d processes for processgroup %d\n", processes, initialPid);
+        if (sleep_us < 128000) {
+            usleep(sleep_us);
+            sleep_us *= 2;
+        } else {
+            SLOGE("failed to kill %d processes for processgroup %d\n",
+                    processes, initialPid);
+            break;
+        }
+    }
+
+    SLOGV("Killed process group uid %d pid %d in %ldms, %d procs remain", uid, initialPid,
+            android::uptimeMillis()-startTime, processes);
+
+    if (processes == 0) {
+        return removeProcessGroup(uid, initialPid);
+    } else {
+        return -1;
+    }
+}
+
+static int mkdirAndChown(const char *path, mode_t mode, uid_t uid, gid_t gid)
+{
+    int ret;
+
+    ret = mkdir(path, 0750);
+    if (ret < 0 && errno != EEXIST) {
+        return -errno;
+    }
+
+    ret = chown(path, AID_SYSTEM, AID_SYSTEM);
+    if (ret < 0) {
+        ret = -errno;
+        rmdir(path);
+        return ret;
+    }
+
+    return 0;
+}
+
+int createProcessGroup(uid_t uid, int initialPid)
+{
+    char path[PROCESSGROUP_MAX_PATH_LEN] = {0};
+    int ret;
+
+    convertUidToPath(path, sizeof(path), uid);
+
+    ret = mkdirAndChown(path, 0750, AID_SYSTEM, AID_SYSTEM);
+    if (ret < 0) {
+        SLOGE("failed to make and chown %s: %s", path, strerror(-ret));
+        return ret;
+    }
+
+    convertUidPidToPath(path, sizeof(path), uid, initialPid);
+
+    ret = mkdirAndChown(path, 0750, AID_SYSTEM, AID_SYSTEM);
+    if (ret < 0) {
+        SLOGE("failed to make and chown %s: %s", path, strerror(-ret));
+        return ret;
+    }
+
+    strlcat(path, PROCESSGROUP_CGROUP_PROCS_FILE, sizeof(path));
+
+    int fd = open(path, O_WRONLY);
+    if (fd < 0) {
+        ret = -errno;
+        SLOGE("failed to open %s: %s", path, strerror(errno));
+        return ret;
+    }
+
+    char pid[PROCESSGROUP_MAX_PID_LEN + 1] = {0};
+    int len = snprintf(pid, sizeof(pid), "%d", initialPid);
+
+    ret = write(fd, pid, len);
+    if (ret < 0) {
+        ret = -errno;
+        SLOGE("failed to write '%s' to %s: %s", pid, path, strerror(errno));
+    } else {
+        ret = 0;
+    }
+
+    close(fd);
+    return ret;
+}
+
diff --git a/libprocessgroup/processgroup_priv.h b/libprocessgroup/processgroup_priv.h
new file mode 100644
index 0000000..1895bf9
--- /dev/null
+++ b/libprocessgroup/processgroup_priv.h
@@ -0,0 +1,35 @@
+/*
+ *  Copyright 2014 Google, Inc
+ *
+ *  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 _PROCESSGROUP_PRIV_H_
+#define _PROCESSGROUP_PRIV_H_
+
+#define PROCESSGROUP_CGROUP_PATH "/acct"
+#define PROCESSGROUP_UID_PREFIX "uid_"
+#define PROCESSGROUP_PID_PREFIX "pid_"
+#define PROCESSGROUP_CGROUP_PROCS_FILE "/cgroup.procs"
+#define PROCESSGROUP_MAX_UID_LEN 11
+#define PROCESSGROUP_MAX_PID_LEN 11
+#define PROCESSGROUP_MAX_PATH_LEN \
+        (sizeof(PROCESSGROUP_CGROUP_PATH) + \
+         sizeof(PROCESSGROUP_UID_PREFIX) + 1 + \
+         PROCESSGROUP_MAX_UID_LEN + \
+         sizeof(PROCESSGROUP_PID_PREFIX) + 1 + \
+         PROCESSGROUP_MAX_PID_LEN + \
+         sizeof(PROCESSGROUP_CGROUP_PROCS_FILE) + \
+         1)
+
+#endif
diff --git a/libsparse/Android.mk b/libsparse/Android.mk
index 02ab412..0abe33d 100644
--- a/libsparse/Android.mk
+++ b/libsparse/Android.mk
@@ -88,15 +88,18 @@
 include $(BUILD_EXECUTABLE)
 
 
+ifneq ($(HOST_OS),windows)
+
 include $(CLEAR_VARS)
-LOCAL_SRC_FILES := simg2simg.c
-LOCAL_MODULE := simg2simg
+LOCAL_SRC_FILES := append2simg.c
+LOCAL_MODULE := append2simg
 LOCAL_STATIC_LIBRARIES := \
     libsparse_host \
     libz
 LOCAL_CFLAGS := -Werror
 include $(BUILD_HOST_EXECUTABLE)
 
+endif
 
 include $(CLEAR_VARS)
 LOCAL_MODULE := simg_dump.py
diff --git a/libsparse/append2simg.c b/libsparse/append2simg.c
new file mode 100644
index 0000000..65e6cc2
--- /dev/null
+++ b/libsparse/append2simg.c
@@ -0,0 +1,140 @@
+/*
+ * 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.
+ */
+
+#define _FILE_OFFSET_BITS 64
+#define _LARGEFILE64_SOURCE 1
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sparse/sparse.h>
+#include "sparse_file.h"
+#include "backed_block.h"
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+#if defined(__APPLE__) && defined(__MACH__)
+#define lseek64 lseek
+#endif
+#if defined(__APPLE__) && defined(__MACH__)
+#define lseek64 lseek
+#define off64_t off_t
+#endif
+
+void usage()
+{
+    fprintf(stderr, "Usage: append2simg <output> <input>\n");
+}
+
+int main(int argc, char *argv[])
+{
+    int output;
+    int output_block;
+    char *output_path;
+    struct sparse_file *sparse_output;
+
+    int input;
+    char *input_path;
+    off64_t input_len;
+
+    int tmp_fd;
+    char *tmp_path;
+
+    int ret;
+
+    if (argc == 3) {
+        output_path = argv[1];
+        input_path = argv[2];
+    } else {
+        usage();
+        exit(-1);
+    }
+
+    ret = asprintf(&tmp_path, "%s.append2simg", output_path);
+    if (ret < 0) {
+        fprintf(stderr, "Couldn't allocate filename\n");
+        exit(-1);
+    }
+
+    output = open(output_path, O_RDWR | O_BINARY);
+    if (output < 0) {
+        fprintf(stderr, "Couldn't open output file (%s)\n", strerror(errno));
+        exit(-1);
+    }
+
+    sparse_output = sparse_file_import_auto(output, true);
+    if (!sparse_output) {
+        fprintf(stderr, "Couldn't import output file\n");
+        exit(-1);
+    }
+
+    input = open(input_path, O_RDONLY | O_BINARY);
+    if (input < 0) {
+        fprintf(stderr, "Couldn't open input file (%s)\n", strerror(errno));
+        exit(-1);
+    }
+
+    input_len = lseek64(input, 0, SEEK_END);
+    if (input_len < 0) {
+        fprintf(stderr, "Couldn't get input file length (%s)\n", strerror(errno));
+        exit(-1);
+    } else if (input_len % sparse_output->block_size) {
+        fprintf(stderr, "Input file is not a multiple of the output file's block size");
+        exit(-1);
+    }
+    lseek64(input, 0, SEEK_SET);
+
+    output_block = sparse_output->len / sparse_output->block_size;
+    if (sparse_file_add_fd(sparse_output, input, 0, input_len, output_block) < 0) {
+        fprintf(stderr, "Couldn't add input file\n");
+        exit(-1);
+    }
+    sparse_output->len += input_len;
+
+    tmp_fd = open(tmp_path, O_WRONLY | O_CREAT | O_BINARY, 0664);
+    if (tmp_fd < 0) {
+        fprintf(stderr, "Couldn't open temporary file (%s)\n", strerror(errno));
+        exit(-1);
+    }
+
+    lseek64(output, 0, SEEK_SET);
+    if (sparse_file_write(sparse_output, tmp_fd, false, true, false) < 0) {
+        fprintf(stderr, "Failed to write sparse file\n");
+        exit(-1);
+    }
+
+    sparse_file_destroy(sparse_output);
+    close(tmp_fd);
+    close(output);
+    close(input);
+
+    ret = rename(tmp_path, output_path);
+    if (ret < 0) {
+        fprintf(stderr, "Failed to rename temporary file (%s)\n", strerror(errno));
+        exit(-1);
+    }
+
+    free(tmp_path);
+
+    exit(0);
+}
diff --git a/libsuspend/autosuspend.c b/libsuspend/autosuspend.c
index eb1f66e..edd1007 100644
--- a/libsuspend/autosuspend.c
+++ b/libsuspend/autosuspend.c
@@ -38,10 +38,13 @@
         goto out;
     }
 
+/* Remove autosleep so userspace can manager suspend/resume and keep stats */
+#if 0
     autosuspend_ops = autosuspend_autosleep_init();
     if (autosuspend_ops) {
         goto out;
     }
+#endif
 
     autosuspend_ops = autosuspend_wakeup_count_init();
     if (autosuspend_ops) {
diff --git a/libsuspend/autosuspend_wakeup_count.c b/libsuspend/autosuspend_wakeup_count.c
index a88e677..7483a8f 100644
--- a/libsuspend/autosuspend_wakeup_count.c
+++ b/libsuspend/autosuspend_wakeup_count.c
@@ -25,6 +25,7 @@
 #include <unistd.h>
 
 #define LOG_TAG "libsuspend"
+//#define LOG_NDEBUG 0
 #include <cutils/log.h>
 
 #include "autosuspend_ops.h"
@@ -37,6 +38,7 @@
 static pthread_t suspend_thread;
 static sem_t suspend_lockout;
 static const char *sleep_state = "mem";
+static void (*wakeup_func)(void) = NULL;
 
 static void *suspend_thread_func(void *arg __attribute__((unused)))
 {
@@ -80,6 +82,11 @@
             if (ret < 0) {
                 strerror_r(errno, buf, sizeof(buf));
                 ALOGE("Error writing to %s: %s\n", SYS_POWER_STATE, buf);
+            } else {
+                void (*func)(void) = wakeup_func;
+                if (func != NULL) {
+                    (*func)();
+                }
             }
         }
 
@@ -131,6 +138,15 @@
     return ret;
 }
 
+void set_wakeup_callback(void (*func)(void))
+{
+    if (wakeup_func != NULL) {
+        ALOGE("Duplicate wakeup callback applied, keeping original");
+        return;
+    }
+    wakeup_func = func;
+}
+
 struct autosuspend_ops autosuspend_wakeup_count_ops = {
         .enable = autosuspend_wakeup_count_enable,
         .disable = autosuspend_wakeup_count_disable,
diff --git a/libsuspend/include/suspend/autosuspend.h b/libsuspend/include/suspend/autosuspend.h
index f56fc6a..10e3d27 100644
--- a/libsuspend/include/suspend/autosuspend.h
+++ b/libsuspend/include/suspend/autosuspend.h
@@ -43,6 +43,13 @@
  */
 int autosuspend_disable(void);
 
+/*
+ * set_wakeup_callback
+ *
+ * Set a function to be called each time the device wakes up from suspend.
+ */
+void set_wakeup_callback(void (*func)(void));
+
 __END_DECLS
 
 #endif
diff --git a/libsync/tests/Android.mk b/libsync/tests/Android.mk
new file mode 100644
index 0000000..ad20e50
--- /dev/null
+++ b/libsync/tests/Android.mk
@@ -0,0 +1,31 @@
+#
+# Copyright 2014 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+include external/libcxx/libcxx.mk
+LOCAL_CLANG := true
+LOCAL_MODULE := sync-unit-tests
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+LOCAL_CFLAGS += -g -Wall -Werror -std=gnu++11 -Wno-missing-field-initializers -Wno-sign-compare
+LOCAL_SHARED_LIBRARIES += libsync
+LOCAL_STATIC_LIBRARIES += libgtest_main
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/../include
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/..
+LOCAL_SRC_FILES := \
+    sync_test.cpp
+include $(BUILD_NATIVE_TEST)
diff --git a/libsync/tests/sync_test.cpp b/libsync/tests/sync_test.cpp
new file mode 100644
index 0000000..55cd687
--- /dev/null
+++ b/libsync/tests/sync_test.cpp
@@ -0,0 +1,615 @@
+#include <gtest/gtest.h>
+#include <sync/sync.h>
+#include <sw_sync.h>
+#include <fcntl.h>
+#include <vector>
+#include <string>
+#include <cassert>
+#include <iostream>
+#include <unistd.h>
+#include <thread>
+#include <poll.h>
+#include <mutex>
+#include <algorithm>
+#include <tuple>
+#include <random>
+#include <unordered_map>
+
+// TODO: better stress tests?
+// Handle more than 64 fd's simultaneously, i.e. fix sync_fence_info's 4k limit.
+// Handle wraparound in timelines like nvidia.
+
+using namespace std;
+
+namespace {
+
+// C++ wrapper class for sync timeline.
+class SyncTimeline {
+    int m_fd = -1;
+    bool m_fdInitialized = false;
+public:
+    SyncTimeline(const SyncTimeline &) = delete;
+    SyncTimeline& operator=(SyncTimeline&) = delete;
+    SyncTimeline() noexcept {
+        int fd = sw_sync_timeline_create();
+        if (fd == -1)
+            return;
+        m_fdInitialized = true;
+        m_fd = fd;
+    }
+    void destroy() {
+        if (m_fdInitialized) {
+            close(m_fd);
+            m_fd = -1;
+            m_fdInitialized = false;
+        }
+    }
+    ~SyncTimeline() {
+        destroy();
+    }
+    bool isValid() const {
+        if (m_fdInitialized) {
+            int status = fcntl(m_fd, F_GETFD, 0);
+            if (status == 0)
+                return true;
+            else
+                return false;
+        }
+        else {
+            return false;
+        }
+    }
+    int getFd() const {
+        return m_fd;
+    }
+    int inc(int val = 1) {
+        return sw_sync_timeline_inc(m_fd, val);
+    }
+};
+
+struct SyncPointInfo {
+    std::string driverName;
+    std::string objectName;
+    uint64_t timeStampNs;
+    int status; // 1 sig, 0 active, neg is err
+};
+
+// Wrapper class for sync fence.
+class SyncFence {
+    int m_fd = -1;
+    bool m_fdInitialized = false;
+    static int s_fenceCount;
+
+    void setFd(int fd) {
+        m_fd = fd;
+        m_fdInitialized = true;
+    }
+    void clearFd() {
+        m_fd = -1;
+        m_fdInitialized = false;
+    }
+public:
+    bool isValid() const {
+        if (m_fdInitialized) {
+            int status = fcntl(m_fd, F_GETFD, 0);
+            if (status == 0)
+                return true;
+            else
+                return false;
+        }
+        else {
+            return false;
+        }
+    }
+    SyncFence& operator=(SyncFence &&rhs) noexcept {
+        destroy();
+        if (rhs.isValid()) {
+            setFd(rhs.getFd());
+            rhs.clearFd();
+        }
+        return *this;
+    }
+    SyncFence(SyncFence &&fence) noexcept {
+        if (fence.isValid()) {
+            setFd(fence.getFd());
+            fence.clearFd();
+        }
+    }
+    SyncFence(const SyncFence &fence) noexcept {
+        // This is ok, as sync fences are immutable after construction, so a dup
+        // is basically the same thing as a copy.
+        if (fence.isValid()) {
+            int fd = dup(fence.getFd());
+            if (fd == -1)
+                return;
+            setFd(fd);
+        }
+    }
+    SyncFence(const SyncTimeline &timeline,
+              int value,
+              const char *name = nullptr) noexcept {
+        std::string autoName = "allocFence";
+        autoName += s_fenceCount;
+        s_fenceCount++;
+        int fd = sw_sync_fence_create(timeline.getFd(), name ? name : autoName.c_str(), value);
+        if (fd == -1)
+            return;
+        setFd(fd);
+    }
+    SyncFence(const SyncFence &a, const SyncFence &b, const char *name = nullptr) noexcept {
+        std::string autoName = "mergeFence";
+        autoName += s_fenceCount;
+        s_fenceCount++;
+        int fd = sync_merge(name ? name : autoName.c_str(), a.getFd(), b.getFd());
+        if (fd == -1)
+            return;
+        setFd(fd);
+    }
+    SyncFence(const vector<SyncFence> &sources) noexcept {
+        assert(sources.size());
+        SyncFence temp(*begin(sources));
+        for (auto itr = ++begin(sources); itr != end(sources); ++itr) {
+            temp = SyncFence(*itr, temp);
+        }
+        if (temp.isValid()) {
+            setFd(temp.getFd());
+            temp.clearFd();
+        }
+    }
+    void destroy() {
+        if (isValid()) {
+            close(m_fd);
+            clearFd();
+        }
+    }
+    ~SyncFence() {
+        destroy();
+    }
+    int getFd() const {
+        return m_fd;
+    }
+    int wait(int timeout = -1) {
+        return sync_wait(m_fd, timeout);
+    }
+    vector<SyncPointInfo> getInfo() const {
+        struct sync_pt_info *pointInfo = nullptr;
+        vector<SyncPointInfo> fenceInfo;
+        sync_fence_info_data *info = sync_fence_info(getFd());
+        if (!info) {
+            return fenceInfo;
+        }
+        while ((pointInfo = sync_pt_info(info, pointInfo))) {
+            fenceInfo.push_back(SyncPointInfo{
+                pointInfo->driver_name,
+                pointInfo->obj_name,
+                pointInfo->timestamp_ns,
+                pointInfo->status});
+        }
+        sync_fence_info_free(info);
+        return fenceInfo;
+    }
+    int getSize() const {
+        return getInfo().size();
+    }
+    int getSignaledCount() const {
+        return countWithStatus(1);
+    }
+    int getActiveCount() const {
+        return countWithStatus(0);
+    }
+    int getErrorCount() const {
+        return countWithStatus(-1);
+    }
+private:
+    int countWithStatus(int status) const {
+        int count = 0;
+        for (auto &info : getInfo()) {
+            if (info.status == status) {
+                count++;
+            }
+        }
+        return count;
+    }
+};
+
+int SyncFence::s_fenceCount = 0;
+
+TEST(AllocTest, Timeline) {
+    SyncTimeline timeline;
+    ASSERT_TRUE(timeline.isValid());
+}
+
+TEST(AllocTest, Fence) {
+    SyncTimeline timeline;
+    ASSERT_TRUE(timeline.isValid());
+
+    SyncFence fence(timeline, 1);
+    ASSERT_TRUE(fence.isValid());
+}
+
+TEST(AllocTest, FenceNegative) {
+    int timeline = sw_sync_timeline_create();
+    ASSERT_GT(timeline, 0);
+
+    // bad fd.
+    ASSERT_LT(sw_sync_fence_create(-1, "fence", 1), 0);
+
+    // No name - segfaults in user space.
+    // Maybe we should be friendlier here?
+    /*
+    ASSERT_LT(sw_sync_fence_create(timeline, nullptr, 1), 0);
+    */
+    close(timeline);
+}
+
+TEST(FenceTest, OneTimelineWait) {
+    SyncTimeline timeline;
+    ASSERT_TRUE(timeline.isValid());
+
+    SyncFence fence(timeline, 5);
+    ASSERT_TRUE(fence.isValid());
+
+    // Wait on fence until timeout.
+    ASSERT_EQ(fence.wait(0), -1);
+    ASSERT_EQ(errno, ETIME);
+
+    // Advance timeline from 0 -> 1
+    ASSERT_EQ(timeline.inc(1), 0);
+
+    // Wait on fence until timeout.
+    ASSERT_EQ(fence.wait(0), -1);
+    ASSERT_EQ(errno, ETIME);
+
+    // Signal the fence.
+    ASSERT_EQ(timeline.inc(4), 0);
+
+    // Wait successfully.
+    ASSERT_EQ(fence.wait(0), 0);
+
+    // Go even futher, and confirm wait still succeeds.
+    ASSERT_EQ(timeline.inc(10), 0);
+    ASSERT_EQ(fence.wait(0), 0);
+}
+
+TEST(FenceTest, OneTimelinePoll) {
+    SyncTimeline timeline;
+    ASSERT_TRUE(timeline.isValid());
+
+    SyncFence fence(timeline, 100);
+    ASSERT_TRUE(fence.isValid());
+
+    fd_set set;
+    FD_ZERO(&set);
+    FD_SET(fence.getFd(), &set);
+
+    // Poll the fence, and wait till timeout.
+    timeval time = {0};
+    ASSERT_EQ(select(fence.getFd() + 1, &set, nullptr, nullptr, &time), 0);
+
+    // Advance the timeline.
+    timeline.inc(100);
+    timeline.inc(100);
+
+    // Select should return that the fd is read for reading.
+    FD_ZERO(&set);
+    FD_SET(fence.getFd(), &set);
+
+    ASSERT_EQ(select(fence.getFd() + 1, &set, nullptr, nullptr, &time), 1);
+    ASSERT_TRUE(FD_ISSET(fence.getFd(), &set));
+}
+
+TEST(FenceTest, OneTimelineMerge) {
+    SyncTimeline timeline;
+    ASSERT_TRUE(timeline.isValid());
+
+    // create fence a,b,c and then merge them all into fence d.
+    SyncFence a(timeline, 1), b(timeline, 2), c(timeline, 3);
+    ASSERT_TRUE(a.isValid());
+    ASSERT_TRUE(b.isValid());
+    ASSERT_TRUE(c.isValid());
+
+    SyncFence d({a,b,c});
+    ASSERT_TRUE(d.isValid());
+
+    // confirm all fences have one active point (even d).
+    ASSERT_EQ(a.getActiveCount(), 1);
+    ASSERT_EQ(b.getActiveCount(), 1);
+    ASSERT_EQ(c.getActiveCount(), 1);
+    ASSERT_EQ(d.getActiveCount(), 1);
+
+    // confirm that d is not signaled until the max of a,b,c
+    timeline.inc(1);
+    ASSERT_EQ(a.getSignaledCount(), 1);
+    ASSERT_EQ(d.getActiveCount(), 1);
+
+    timeline.inc(1);
+    ASSERT_EQ(b.getSignaledCount(), 1);
+    ASSERT_EQ(d.getActiveCount(), 1);
+
+    timeline.inc(1);
+    ASSERT_EQ(c.getSignaledCount(), 1);
+    ASSERT_EQ(d.getActiveCount(), 0);
+    ASSERT_EQ(d.getSignaledCount(), 1);
+}
+
+TEST(FenceTest, MergeSameFence) {
+    SyncTimeline timeline;
+    ASSERT_TRUE(timeline.isValid());
+
+    SyncFence fence(timeline, 5);
+    ASSERT_TRUE(fence.isValid());
+
+    SyncFence selfMergeFence(fence, fence);
+    ASSERT_TRUE(selfMergeFence.isValid());
+
+    ASSERT_EQ(selfMergeFence.getSignaledCount(), 0);
+
+    timeline.inc(5);
+    ASSERT_EQ(selfMergeFence.getSignaledCount(), 1);
+}
+
+TEST(FenceTest, WaitOnDestroyedTimeline) {
+    SyncTimeline timeline;
+    ASSERT_TRUE(timeline.isValid());
+
+    SyncFence fenceSig(timeline, 100);
+    SyncFence fenceKill(timeline, 200);
+
+    // Spawn a thread to wait on a fence when the timeline is killed.
+    thread waitThread{
+        [&]() {
+            ASSERT_EQ(timeline.inc(100), 0);
+
+            ASSERT_EQ(fenceKill.wait(-1), -1);
+            ASSERT_EQ(errno, ENOENT);
+        }
+    };
+
+    // Wait for the thread to spool up.
+    fenceSig.wait();
+
+    // Kill the timeline.
+    timeline.destroy();
+
+    // wait for the thread to clean up.
+    waitThread.join();
+}
+
+TEST(FenceTest, PollOnDestroyedTimeline) {
+    SyncTimeline timeline;
+    ASSERT_TRUE(timeline.isValid());
+
+    SyncFence fenceSig(timeline, 100);
+    SyncFence fenceKill(timeline, 200);
+
+    // Spawn a thread to wait on a fence when the timeline is killed.
+    thread waitThread{
+        [&]() {
+            ASSERT_EQ(timeline.inc(100), 0);
+
+            // Wait on the fd.
+            struct pollfd fds;
+            fds.fd = fenceKill.getFd();
+            fds.events = POLLIN | POLLERR;
+            ASSERT_EQ(poll(&fds, 1, -1), 1);
+            ASSERT_TRUE(fds.revents & POLLERR);
+        }
+    };
+
+    // Wait for the thread to spool up.
+    fenceSig.wait();
+
+    // Kill the timeline.
+    timeline.destroy();
+
+    // wait for the thread to clean up.
+    waitThread.join();
+}
+
+TEST(FenceTest, MultiTimelineWait) {
+    SyncTimeline timelineA, timelineB, timelineC;
+
+    SyncFence fenceA(timelineA, 5);
+    SyncFence fenceB(timelineB, 5);
+    SyncFence fenceC(timelineC, 5);
+
+    // Make a larger fence using 3 other fences from different timelines.
+    SyncFence mergedFence({fenceA, fenceB, fenceC});
+    ASSERT_TRUE(mergedFence.isValid());
+
+    // Confirm fence isn't signaled
+    ASSERT_EQ(mergedFence.getActiveCount(), 3);
+    ASSERT_EQ(mergedFence.wait(0), -1);
+    ASSERT_EQ(errno, ETIME);
+
+    timelineA.inc(5);
+    ASSERT_EQ(mergedFence.getActiveCount(), 2);
+    ASSERT_EQ(mergedFence.getSignaledCount(), 1);
+
+    timelineB.inc(5);
+    ASSERT_EQ(mergedFence.getActiveCount(), 1);
+    ASSERT_EQ(mergedFence.getSignaledCount(), 2);
+
+    timelineC.inc(5);
+    ASSERT_EQ(mergedFence.getActiveCount(), 0);
+    ASSERT_EQ(mergedFence.getSignaledCount(), 3);
+
+    // confirm you can successfully wait.
+    ASSERT_EQ(mergedFence.wait(100), 0);
+}
+
+TEST(StressTest, TwoThreadsSharedTimeline) {
+    const int iterations = 1 << 16;
+    int counter = 0;
+    SyncTimeline timeline;
+    ASSERT_TRUE(timeline.isValid());
+
+    // Use a single timeline to synchronize two threads
+    // hammmering on the same counter.
+    auto threadMain = [&](int threadId) {
+        for (int i = 0; i < iterations; i++) {
+            SyncFence fence(timeline, i * 2 + threadId);
+            ASSERT_TRUE(fence.isValid());
+
+            // Wait on the prior thread to complete.
+            ASSERT_EQ(fence.wait(), 0);
+
+            // Confirm the previous thread's writes are visible and then inc.
+            ASSERT_EQ(counter, i * 2 + threadId);
+            counter++;
+
+            // Kick off the other thread.
+            ASSERT_EQ(timeline.inc(), 0);
+        }
+    };
+
+    thread a{threadMain, 0};
+    thread b{threadMain, 1};
+    a.join();
+    b.join();
+
+    // make sure the threads did not trample on one another.
+    ASSERT_EQ(counter, iterations * 2);
+}
+
+class ConsumerStressTest : public ::testing::TestWithParam<int> {};
+
+TEST_P(ConsumerStressTest, MultiProducerSingleConsumer) {
+    mutex lock;
+    int counter = 0;
+    int iterations = 1 << 12;
+
+    vector<SyncTimeline> producerTimelines(GetParam());
+    vector<thread> threads;
+    SyncTimeline consumerTimeline;
+
+    // Producer threads run this lambda.
+    auto threadMain = [&](int threadId) {
+        for (int i = 0; i < iterations; i++) {
+            SyncFence fence(consumerTimeline, i);
+            ASSERT_TRUE(fence.isValid());
+
+            // Wait for the consumer to finish. Use alternate
+            // means of waiting on the fence.
+            if ((iterations + threadId) % 8 != 0) {
+                ASSERT_EQ(fence.wait(), 0);
+            }
+            else {
+                while (fence.getSignaledCount() != 1) {
+                    ASSERT_EQ(fence.getErrorCount(), 0);
+                }
+            }
+
+            // Every producer increments the counter, the consumer checks + erases it.
+            lock.lock();
+            counter++;
+            lock.unlock();
+
+            ASSERT_EQ(producerTimelines[threadId].inc(), 0);
+        }
+    };
+
+    for (int i = 0; i < GetParam(); i++) {
+        threads.push_back(thread{threadMain, i});
+    }
+
+    // Consumer thread runs this loop.
+    for (int i = 1; i <= iterations; i++) {
+        // Create a fence representing all producers final timelines.
+        vector<SyncFence> fences;
+        for (auto& timeline : producerTimelines) {
+            fences.push_back(SyncFence(timeline, i));
+        }
+        SyncFence mergeFence(fences);
+        ASSERT_TRUE(mergeFence.isValid());
+
+        // Make sure we see an increment from every producer thread. Vary
+        // the means by which we wait.
+        if (iterations % 8 != 0) {
+            ASSERT_EQ(mergeFence.wait(), 0);
+        }
+        else {
+            while (mergeFence.getSignaledCount() != mergeFence.getSize()) {
+                ASSERT_EQ(mergeFence.getErrorCount(), 0);
+            }
+        }
+        ASSERT_EQ(counter, GetParam()*i);
+
+        // Release the producer threads.
+        ASSERT_EQ(consumerTimeline.inc(), 0);
+    }
+
+    for_each(begin(threads), end(threads), [](thread& thread) { thread.join(); });
+}
+INSTANTIATE_TEST_CASE_P(
+    ParameterizedStressTest,
+    ConsumerStressTest,
+    ::testing::Values(2,4,16));
+
+class MergeStressTest : public ::testing::TestWithParam<tuple<int, int>> {};
+
+template <typename K, typename V> using dict = unordered_map<K,V>;
+
+TEST_P(MergeStressTest, RandomMerge) {
+    int timelineCount = get<0>(GetParam());
+    int mergeCount = get<1>(GetParam());
+
+    vector<SyncTimeline> timelines(timelineCount);
+
+    default_random_engine generator;
+    uniform_int_distribution<int> timelineDist(0, timelines.size()-1);
+    uniform_int_distribution<int> syncPointDist(0, numeric_limits<int>::max());
+
+    SyncFence fence(timelines[0], 0);
+    ASSERT_TRUE(fence.isValid());
+
+    unordered_map<int, int> fenceMap;
+    fenceMap.insert(make_tuple(0, 0));
+
+    // Randomly create syncpoints out of a fixed set of timelines, and merge them together.
+    for (int i = 0; i < mergeCount; i++) {
+
+        // Generate syncpoint.
+        int timelineOffset = timelineDist(generator);
+        const SyncTimeline& timeline = timelines[timelineOffset];
+        int syncPoint = syncPointDist(generator);
+
+        // Keep track of the latest syncpoint in each timeline.
+        auto itr = fenceMap.find(timelineOffset);
+        if (itr == end(fenceMap)) {
+            fenceMap.insert(tie(timelineOffset, syncPoint));
+        }
+        else {
+            int oldSyncPoint = itr->second;
+            fenceMap.erase(itr);
+            fenceMap.insert(tie(timelineOffset, max(syncPoint, oldSyncPoint)));
+        }
+
+        // Merge.
+        fence = SyncFence(fence, SyncFence(timeline, syncPoint));
+        ASSERT_TRUE(fence.isValid());
+    }
+
+    // Confirm our map matches the fence.
+    ASSERT_EQ(fence.getSize(), fenceMap.size());
+
+    // Trigger the merged fence.
+    for (auto& item: fenceMap) {
+        ASSERT_EQ(fence.wait(0), -1);
+        ASSERT_EQ(errno, ETIME);
+
+        // Increment the timeline to the last syncpoint.
+        timelines[item.first].inc(item.second);
+    }
+
+    // Check that the fence is triggered.
+    ASSERT_EQ(fence.wait(0), 0);
+}
+
+INSTANTIATE_TEST_CASE_P(
+    ParameterizedMergeStressTest,
+    MergeStressTest,
+    ::testing::Combine(::testing::Values(16,32), ::testing::Values(32, 1024, 1024*32)));
+
+}
+
diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp
index 1c9c70a..9d596ef 100644
--- a/libsysutils/src/NetlinkEvent.cpp
+++ b/libsysutils/src/NetlinkEvent.cpp
@@ -29,6 +29,8 @@
 #include <net/if.h>
 
 #include <linux/if.h>
+#include <linux/if_addr.h>
+#include <linux/if_link.h>
 #include <linux/netfilter/nfnetlink.h>
 #include <linux/netfilter_ipv4/ipt_ULOG.h>
 /* From kernel's net/netfilter/xt_quota2.c */
@@ -46,6 +48,8 @@
 const int NetlinkEvent::NlActionAddressUpdated = 6;
 const int NetlinkEvent::NlActionAddressRemoved = 7;
 const int NetlinkEvent::NlActionRdnss = 8;
+const int NetlinkEvent::NlActionRouteUpdated = 9;
+const int NetlinkEvent::NlActionRouteRemoved = 10;
 
 NetlinkEvent::NetlinkEvent() {
     mAction = NlActionUnknown;
@@ -78,32 +82,109 @@
 }
 
 /*
+ * Returns the message name for a message in the NETLINK_ROUTE family, or NULL
+ * if parsing that message is not supported.
+ */
+static const char *rtMessageName(int type) {
+#define NL_EVENT_RTM_NAME(rtm) case rtm: return #rtm;
+    switch (type) {
+        NL_EVENT_RTM_NAME(RTM_NEWLINK);
+        NL_EVENT_RTM_NAME(RTM_DELLINK);
+        NL_EVENT_RTM_NAME(RTM_NEWADDR);
+        NL_EVENT_RTM_NAME(RTM_DELADDR);
+        NL_EVENT_RTM_NAME(RTM_NEWROUTE);
+        NL_EVENT_RTM_NAME(RTM_DELROUTE);
+        NL_EVENT_RTM_NAME(RTM_NEWNDUSEROPT);
+        NL_EVENT_RTM_NAME(QLOG_NL_EVENT);
+        default:
+            return NULL;
+    }
+#undef NL_EVENT_RTM_NAME
+}
+
+/*
+ * Checks that a binary NETLINK_ROUTE message is long enough for a payload of
+ * size bytes.
+ */
+static bool checkRtNetlinkLength(const struct nlmsghdr *nh, size_t size) {
+    if (nh->nlmsg_len < NLMSG_LENGTH(size)) {
+        SLOGE("Got a short %s message\n", rtMessageName(nh->nlmsg_type));
+        return false;
+    }
+    return true;
+}
+
+/*
+ * Utility function to log errors.
+ */
+static bool maybeLogDuplicateAttribute(bool isDup,
+                                       const char *attributeName,
+                                       const char *messageName) {
+    if (isDup) {
+        SLOGE("Multiple %s attributes in %s, ignoring\n", attributeName, messageName);
+        return true;
+    }
+    return false;
+}
+
+/*
+ * Parse a RTM_NEWLINK message.
+ */
+bool NetlinkEvent::parseIfInfoMessage(const struct nlmsghdr *nh) {
+    struct ifinfomsg *ifi = (struct ifinfomsg *) NLMSG_DATA(nh);
+    if (!checkRtNetlinkLength(nh, sizeof(*ifi)))
+        return false;
+
+    if ((ifi->ifi_flags & IFF_LOOPBACK) != 0) {
+        return false;
+    }
+
+    int len = IFLA_PAYLOAD(nh);
+    struct rtattr *rta;
+    for (rta = IFLA_RTA(ifi); RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
+        switch(rta->rta_type) {
+            case IFLA_IFNAME:
+                asprintf(&mParams[0], "INTERFACE=%s", (char *) RTA_DATA(rta));
+                mAction = (ifi->ifi_flags & IFF_LOWER_UP) ?  NlActionLinkUp :
+                                                             NlActionLinkDown;
+                mSubsystem = strdup("net");
+                return true;
+        }
+    }
+
+    return false;
+}
+
+/*
  * Parse a RTM_NEWADDR or RTM_DELADDR message.
  */
-bool NetlinkEvent::parseIfAddrMessage(int type, struct ifaddrmsg *ifaddr,
-                                      int rtasize) {
-    struct rtattr *rta;
+bool NetlinkEvent::parseIfAddrMessage(const struct nlmsghdr *nh) {
+    struct ifaddrmsg *ifaddr = (struct ifaddrmsg *) NLMSG_DATA(nh);
     struct ifa_cacheinfo *cacheinfo = NULL;
     char addrstr[INET6_ADDRSTRLEN] = "";
+    char ifname[IFNAMSIZ];
+
+    if (!checkRtNetlinkLength(nh, sizeof(*ifaddr)))
+        return false;
 
     // Sanity check.
+    int type = nh->nlmsg_type;
     if (type != RTM_NEWADDR && type != RTM_DELADDR) {
         SLOGE("parseIfAddrMessage on incorrect message type 0x%x\n", type);
         return false;
     }
 
     // For log messages.
-    const char *msgtype = (type == RTM_NEWADDR) ? "RTM_NEWADDR" : "RTM_DELADDR";
+    const char *msgtype = rtMessageName(type);
 
-    for (rta = IFA_RTA(ifaddr); RTA_OK(rta, rtasize);
-         rta = RTA_NEXT(rta, rtasize)) {
+    struct rtattr *rta;
+    int len = IFA_PAYLOAD(nh);
+    for (rta = IFA_RTA(ifaddr); RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
         if (rta->rta_type == IFA_ADDRESS) {
             // Only look at the first address, because we only support notifying
             // one change at a time.
-            if (*addrstr != '\0') {
-                SLOGE("Multiple IFA_ADDRESSes in %s, ignoring\n", msgtype);
+            if (maybeLogDuplicateAttribute(*addrstr != '\0', "IFA_ADDRESS", msgtype))
                 continue;
-            }
 
             // Convert the IP address to a string.
             if (ifaddr->ifa_family == AF_INET) {
@@ -128,28 +209,15 @@
             }
 
             // Find the interface name.
-            char ifname[IFNAMSIZ + 1];
             if (!if_indextoname(ifaddr->ifa_index, ifname)) {
                 SLOGE("Unknown ifindex %d in %s", ifaddr->ifa_index, msgtype);
                 return false;
             }
 
-            // Fill in interface information.
-            mAction = (type == RTM_NEWADDR) ? NlActionAddressUpdated :
-                                              NlActionAddressRemoved;
-            mSubsystem = strdup("net");
-            asprintf(&mParams[0], "ADDRESS=%s/%d", addrstr,
-                     ifaddr->ifa_prefixlen);
-            asprintf(&mParams[1], "INTERFACE=%s", ifname);
-            asprintf(&mParams[2], "FLAGS=%u", ifaddr->ifa_flags);
-            asprintf(&mParams[3], "SCOPE=%u", ifaddr->ifa_scope);
         } else if (rta->rta_type == IFA_CACHEINFO) {
             // Address lifetime information.
-            if (cacheinfo) {
-                // We only support one address.
-                SLOGE("Multiple IFA_CACHEINFOs in %s, ignoring\n", msgtype);
+            if (maybeLogDuplicateAttribute(cacheinfo, "IFA_CACHEINFO", msgtype))
                 continue;
-            }
 
             if (RTA_PAYLOAD(rta) < sizeof(*cacheinfo)) {
                 SLOGE("Short IFA_CACHEINFO (%zu vs. %zu bytes) in %s",
@@ -158,10 +226,6 @@
             }
 
             cacheinfo = (struct ifa_cacheinfo *) RTA_DATA(rta);
-            asprintf(&mParams[4], "PREFERRED=%u", cacheinfo->ifa_prefered);
-            asprintf(&mParams[5], "VALID=%u", cacheinfo->ifa_valid);
-            asprintf(&mParams[6], "CSTAMP=%u", cacheinfo->cstamp);
-            asprintf(&mParams[7], "TSTAMP=%u", cacheinfo->tstamp);
         }
     }
 
@@ -170,14 +234,145 @@
         return false;
     }
 
+    // Fill in netlink event information.
+    mAction = (type == RTM_NEWADDR) ? NlActionAddressUpdated :
+                                      NlActionAddressRemoved;
+    mSubsystem = strdup("net");
+    asprintf(&mParams[0], "ADDRESS=%s/%d", addrstr,
+             ifaddr->ifa_prefixlen);
+    asprintf(&mParams[1], "INTERFACE=%s", ifname);
+    asprintf(&mParams[2], "FLAGS=%u", ifaddr->ifa_flags);
+    asprintf(&mParams[3], "SCOPE=%u", ifaddr->ifa_scope);
+
+    if (cacheinfo) {
+        asprintf(&mParams[4], "PREFERRED=%u", cacheinfo->ifa_prefered);
+        asprintf(&mParams[5], "VALID=%u", cacheinfo->ifa_valid);
+        asprintf(&mParams[6], "CSTAMP=%u", cacheinfo->cstamp);
+        asprintf(&mParams[7], "TSTAMP=%u", cacheinfo->tstamp);
+    }
+
+    return true;
+}
+
+/*
+ * Parse a QLOG_NL_EVENT message.
+ */
+bool NetlinkEvent::parseUlogPacketMessage(const struct nlmsghdr *nh) {
+    const char *devname;
+    ulog_packet_msg_t *pm = (ulog_packet_msg_t *) NLMSG_DATA(nh);
+    if (!checkRtNetlinkLength(nh, sizeof(*pm)))
+        return false;
+
+    devname = pm->indev_name[0] ? pm->indev_name : pm->outdev_name;
+    asprintf(&mParams[0], "ALERT_NAME=%s", pm->prefix);
+    asprintf(&mParams[1], "INTERFACE=%s", devname);
+    mSubsystem = strdup("qlog");
+    mAction = NlActionChange;
+    return true;
+}
+
+/*
+ * Parse a RTM_NEWROUTE or RTM_DELROUTE message.
+ */
+bool NetlinkEvent::parseRtMessage(const struct nlmsghdr *nh) {
+    uint8_t type = nh->nlmsg_type;
+    const char *msgname = rtMessageName(type);
+
+    // Sanity check.
+    if (type != RTM_NEWROUTE && type != RTM_DELROUTE) {
+        SLOGE("%s: incorrect message type %d (%s)\n", __func__, type, msgname);
+        return false;
+    }
+
+    struct rtmsg *rtm = (struct rtmsg *) NLMSG_DATA(nh);
+    if (!checkRtNetlinkLength(nh, sizeof(*rtm)))
+        return false;
+
+    if (// Ignore static routes we've set up ourselves.
+        (rtm->rtm_protocol != RTPROT_KERNEL &&
+         rtm->rtm_protocol != RTPROT_RA) ||
+        // We're only interested in global unicast routes.
+        (rtm->rtm_scope != RT_SCOPE_UNIVERSE) ||
+        (rtm->rtm_type != RTN_UNICAST) ||
+        // We don't support source routing.
+        (rtm->rtm_src_len != 0) ||
+        // Cloned routes aren't real routes.
+        (rtm->rtm_flags & RTM_F_CLONED)) {
+        return false;
+    }
+
+    int family = rtm->rtm_family;
+    int prefixLength = rtm->rtm_dst_len;
+
+    // Currently we only support: destination, (one) next hop, ifindex.
+    char dst[INET6_ADDRSTRLEN] = "";
+    char gw[INET6_ADDRSTRLEN] = "";
+    char dev[IFNAMSIZ] = "";
+
+    size_t len = RTM_PAYLOAD(nh);
+    struct rtattr *rta;
+    for (rta = RTM_RTA(rtm); RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
+        switch (rta->rta_type) {
+            case RTA_DST:
+                if (maybeLogDuplicateAttribute(*dst, "RTA_DST", msgname))
+                    continue;
+                if (!inet_ntop(family, RTA_DATA(rta), dst, sizeof(dst)))
+                    return false;
+                continue;
+            case RTA_GATEWAY:
+                if (maybeLogDuplicateAttribute(*gw, "RTA_GATEWAY", msgname))
+                    continue;
+                if (!inet_ntop(family, RTA_DATA(rta), gw, sizeof(gw)))
+                    return false;
+                continue;
+            case RTA_OIF:
+                if (maybeLogDuplicateAttribute(*dev, "RTA_OIF", msgname))
+                    continue;
+                if (!if_indextoname(* (int *) RTA_DATA(rta), dev))
+                    return false;
+            default:
+                continue;
+        }
+    }
+
+   // If there's no RTA_DST attribute, then:
+   // - If the prefix length is zero, it's the default route.
+   // - If the prefix length is nonzero, there's something we don't understand.
+   //   Ignore the event.
+   if (!*dst && !prefixLength) {
+        if (family == AF_INET) {
+            strncpy(dst, "0.0.0.0", sizeof(dst));
+        } else if (family == AF_INET6) {
+            strncpy(dst, "::", sizeof(dst));
+        }
+    }
+
+    // A useful route must have a destination and at least either a gateway or
+    // an interface.
+    if (!*dst || (!*gw && !*dev))
+        return false;
+
+    // Fill in netlink event information.
+    mAction = (type == RTM_NEWROUTE) ? NlActionRouteUpdated :
+                                       NlActionRouteRemoved;
+    mSubsystem = strdup("net");
+    asprintf(&mParams[0], "ROUTE=%s/%d", dst, prefixLength);
+    asprintf(&mParams[1], "GATEWAY=%s", (*gw) ? gw : "");
+    asprintf(&mParams[2], "INTERFACE=%s", (*dev) ? dev : "");
+
     return true;
 }
 
 /*
  * Parse a RTM_NEWNDUSEROPT message.
  */
-bool NetlinkEvent::parseNdUserOptMessage(struct nduseroptmsg *msg, int len) {
+bool NetlinkEvent::parseNdUserOptMessage(const struct nlmsghdr *nh) {
+    struct nduseroptmsg *msg = (struct nduseroptmsg *) NLMSG_DATA(nh);
+    if (!checkRtNetlinkLength(nh, sizeof(*msg)))
+        return false;
+
     // Check the length is valid.
+    int len = NLMSG_PAYLOAD(nh, sizeof(*msg));
     if (msg->nduseropt_opts_len > len) {
         SLOGE("RTM_NEWNDUSEROPT invalid length %d > %d\n",
               msg->nduseropt_opts_len, len);
@@ -200,7 +395,7 @@
     }
 
     // Find the interface name.
-    char ifname[IFNAMSIZ + 1];
+    char ifname[IFNAMSIZ];
     if (!if_indextoname(msg->nduseropt_ifindex, ifname)) {
         SLOGE("RTM_NEWNDUSEROPT on unknown ifindex %d\n",
               msg->nduseropt_ifindex);
@@ -273,6 +468,14 @@
 
 /*
  * Parse a binary message from a NETLINK_ROUTE netlink socket.
+ *
+ * Note that this function can only parse one message, because the message's
+ * content has to be stored in the class's member variables (mAction,
+ * mSubsystem, etc.). Invalid or unrecognized messages are skipped, but if
+ * there are multiple valid messages in the buffer, only the first one will be
+ * returned.
+ *
+ * TODO: consider only ever looking at the first message.
  */
 bool NetlinkEvent::parseBinaryNetlinkMessage(char *buffer, int size) {
     const struct nlmsghdr *nh;
@@ -281,93 +484,37 @@
          NLMSG_OK(nh, (unsigned) size) && (nh->nlmsg_type != NLMSG_DONE);
          nh = NLMSG_NEXT(nh, size)) {
 
+        if (!rtMessageName(nh->nlmsg_type)) {
+            SLOGD("Unexpected netlink message type %d\n", nh->nlmsg_type);
+            continue;
+        }
+
         if (nh->nlmsg_type == RTM_NEWLINK) {
-            int len = nh->nlmsg_len - sizeof(*nh);
-            struct ifinfomsg *ifi;
-
-            if (sizeof(*ifi) > (size_t) len) {
-                SLOGE("Got a short RTM_NEWLINK message\n");
-                continue;
-            }
-
-            ifi = (ifinfomsg *)NLMSG_DATA(nh);
-            if ((ifi->ifi_flags & IFF_LOOPBACK) != 0) {
-                continue;
-            }
-
-            struct rtattr *rta = (struct rtattr *)
-              ((char *) ifi + NLMSG_ALIGN(sizeof(*ifi)));
-            len = NLMSG_PAYLOAD(nh, sizeof(*ifi));
-
-            while(RTA_OK(rta, len)) {
-                switch(rta->rta_type) {
-                case IFLA_IFNAME:
-                    char buffer[16 + IFNAMSIZ];
-                    snprintf(buffer, sizeof(buffer), "INTERFACE=%s",
-                             (char *) RTA_DATA(rta));
-                    mParams[0] = strdup(buffer);
-                    mAction = (ifi->ifi_flags & IFF_LOWER_UP) ?
-                      NlActionLinkUp : NlActionLinkDown;
-                    mSubsystem = strdup("net");
-                    break;
-                }
-
-                rta = RTA_NEXT(rta, len);
-            }
+            if (parseIfInfoMessage(nh))
+                return true;
 
         } else if (nh->nlmsg_type == QLOG_NL_EVENT) {
-            char *devname;
-            ulog_packet_msg_t *pm;
-            size_t len = nh->nlmsg_len - sizeof(*nh);
-            if (sizeof(*pm) > len) {
-                SLOGE("Got a short QLOG message\n");
-                continue;
-            }
-            pm = (ulog_packet_msg_t *)NLMSG_DATA(nh);
-            devname = pm->indev_name[0] ? pm->indev_name : pm->outdev_name;
-            asprintf(&mParams[0], "ALERT_NAME=%s", pm->prefix);
-            asprintf(&mParams[1], "INTERFACE=%s", devname);
-            mSubsystem = strdup("qlog");
-            mAction = NlActionChange;
+            if (parseUlogPacketMessage(nh))
+                return true;
 
         } else if (nh->nlmsg_type == RTM_NEWADDR ||
                    nh->nlmsg_type == RTM_DELADDR) {
-            int len = nh->nlmsg_len - sizeof(*nh);
-            struct ifaddrmsg *ifa;
+            if (parseIfAddrMessage(nh))
+                return true;
 
-            if (sizeof(*ifa) > (size_t) len) {
-                SLOGE("Got a short RTM_xxxADDR message\n");
-                continue;
-            }
-
-            ifa = (ifaddrmsg *)NLMSG_DATA(nh);
-            size_t rtasize = IFA_PAYLOAD(nh);
-            if (!parseIfAddrMessage(nh->nlmsg_type, ifa, rtasize)) {
-                continue;
-            }
+        } else if (nh->nlmsg_type == RTM_NEWROUTE ||
+                   nh->nlmsg_type == RTM_DELROUTE) {
+            if (parseRtMessage(nh))
+                return true;
 
         } else if (nh->nlmsg_type == RTM_NEWNDUSEROPT) {
-            int len = nh->nlmsg_len - sizeof(*nh);
-            struct nduseroptmsg *ndmsg = (struct nduseroptmsg *) NLMSG_DATA(nh);
+            if (parseNdUserOptMessage(nh))
+                return true;
 
-            if (sizeof(*ndmsg) > (size_t) len) {
-                SLOGE("Got a short RTM_NEWNDUSEROPT message\n");
-                continue;
-            }
-
-            size_t optsize = NLMSG_PAYLOAD(nh, sizeof(*ndmsg));
-            if (!parseNdUserOptMessage(ndmsg, optsize)) {
-                continue;
-            }
-
-
-        } else {
-                SLOGD("Unexpected netlink message. type=0x%x\n",
-                      nh->nlmsg_type);
         }
     }
 
-    return true;
+    return false;
 }
 
 /* If the string between 'str' and 'end' begins with 'prefixlen' characters
diff --git a/libsysutils/src/NetlinkListener.cpp b/libsysutils/src/NetlinkListener.cpp
index 9c447ca..81c5cc2 100644
--- a/libsysutils/src/NetlinkListener.cpp
+++ b/libsysutils/src/NetlinkListener.cpp
@@ -57,10 +57,12 @@
     }
 
     NetlinkEvent *evt = new NetlinkEvent();
-    if (!evt->decode(mBuffer, count, mFormat)) {
-        SLOGE("Error decoding NetlinkEvent");
-    } else {
+    if (evt->decode(mBuffer, count, mFormat)) {
         onEvent(evt);
+    } else if (mFormat != NETLINK_FORMAT_BINARY) {
+        // Don't complain if parseBinaryNetlinkMessage returns false. That can
+        // just mean that the buffer contained no messages we're interested in.
+        SLOGE("Error decoding NetlinkEvent");
     }
 
     delete evt;
diff --git a/libusbhost/usbhost.c b/libusbhost/usbhost.c
index cd8000a..684f401 100644
--- a/libusbhost/usbhost.c
+++ b/libusbhost/usbhost.c
@@ -454,6 +454,8 @@
     int i, result;
     int languageCount = 0;
 
+    if (id == 0) return NULL;
+
     string[0] = 0;
     memset(languages, 0, sizeof(languages));
 
@@ -487,31 +489,19 @@
 char* usb_device_get_manufacturer_name(struct usb_device *device)
 {
     struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc;
-
-    if (desc->iManufacturer)
-        return usb_device_get_string(device, desc->iManufacturer);
-    else
-        return NULL;
+    return usb_device_get_string(device, desc->iManufacturer);
 }
 
 char* usb_device_get_product_name(struct usb_device *device)
 {
     struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc;
-
-    if (desc->iProduct)
-        return usb_device_get_string(device, desc->iProduct);
-    else
-        return NULL;
+    return usb_device_get_string(device, desc->iProduct);
 }
 
 char* usb_device_get_serial(struct usb_device *device)
 {
     struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc;
-
-    if (desc->iSerialNumber)
-        return usb_device_get_string(device, desc->iSerialNumber);
-    else
-        return NULL;
+    return usb_device_get_string(device, desc->iSerialNumber);
 }
 
 int usb_device_is_writeable(struct usb_device *device)
@@ -557,6 +547,21 @@
     return ioctl(device->fd, USBDEVFS_IOCTL, &ctl);
 }
 
+int usb_device_set_configuration(struct usb_device *device, int configuration)
+{
+    return ioctl(device->fd, USBDEVFS_SETCONFIGURATION, &configuration);
+}
+
+int usb_device_set_interface(struct usb_device *device, unsigned int interface,
+                            unsigned int alt_setting)
+{
+    struct usbdevfs_setinterface ctl;
+
+    ctl.interface = interface;
+    ctl.altsetting = alt_setting;
+    return ioctl(device->fd, USBDEVFS_SETINTERFACE, &ctl);
+}
+
 int usb_device_control_transfer(struct usb_device *device,
                             int requestType,
                             int request,
@@ -690,6 +695,6 @@
 int usb_request_cancel(struct usb_request *req)
 {
     struct usbdevfs_urb *urb = ((struct usbdevfs_urb*)req->private_data);
-    return ioctl(req->dev->fd, USBDEVFS_DISCARDURB, &urb);
+    return ioctl(req->dev->fd, USBDEVFS_DISCARDURB, urb);
 }
 
diff --git a/libutils/Android.mk b/libutils/Android.mk
index 9a50147..b1dc1f8 100644
--- a/libutils/Android.mk
+++ b/libutils/Android.mk
@@ -26,6 +26,7 @@
 	LinearAllocator.cpp \
 	LinearTransform.cpp \
 	Log.cpp \
+	NativeHandle.cpp \
 	Printer.cpp \
 	ProcessCallStack.cpp \
 	PropertyMap.cpp \
@@ -73,19 +74,6 @@
 include $(BUILD_HOST_STATIC_LIBRARY)
 
 
-# For the host, 64-bit
-# =====================================================
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= $(commonSources)
-ifeq ($(HOST_OS), linux)
-LOCAL_SRC_FILES += Looper.cpp
-endif
-LOCAL_MODULE:= lib64utils
-LOCAL_STATIC_LIBRARIES := liblog
-LOCAL_CFLAGS += $(host_commonCflags) -m64
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-
 # For the device, static
 # =====================================================
 include $(CLEAR_VARS)
@@ -103,7 +91,7 @@
 LOCAL_CFLAGS += -Werror
 
 LOCAL_C_INCLUDES += \
-		bionic/libc/private \
+		bionic/libc \
 		external/zlib
 
 LOCAL_STATIC_LIBRARIES := \
diff --git a/libutils/BlobCache.cpp b/libutils/BlobCache.cpp
index f00bf14..0ea09cf 100644
--- a/libutils/BlobCache.cpp
+++ b/libutils/BlobCache.cpp
@@ -31,7 +31,7 @@
 static const uint32_t blobCacheMagic = ('_' << 24) + ('B' << 16) + ('b' << 8) + '$';
 
 // BlobCache::Header::mBlobCacheVersion value
-static const uint32_t blobCacheVersion = 1;
+static const uint32_t blobCacheVersion = 2;
 
 // BlobCache::Header::mDeviceVersion value
 static const uint32_t blobCacheDeviceVersion = 1;
@@ -165,14 +165,13 @@
 }
 
 size_t BlobCache::getFlattenedSize() const {
-    size_t size = sizeof(Header);
+    size_t size = align4(sizeof(Header));
     for (size_t i = 0; i < mCacheEntries.size(); i++) {
         const CacheEntry& e(mCacheEntries[i]);
         sp<Blob> keyBlob = e.getKey();
         sp<Blob> valueBlob = e.getValue();
-        size = align4(size);
-        size += sizeof(EntryHeader) + keyBlob->getSize() +
-                valueBlob->getSize();
+        size += align4(sizeof(EntryHeader) + keyBlob->getSize() +
+                       valueBlob->getSize());
     }
     return size;
 }
@@ -200,7 +199,8 @@
         size_t valueSize = valueBlob->getSize();
 
         size_t entrySize = sizeof(EntryHeader) + keySize + valueSize;
-        if (byteOffset + entrySize > size) {
+        size_t totalSize = align4(entrySize);
+        if (byteOffset + totalSize > size) {
             ALOGE("flatten: not enough room for cache entries");
             return BAD_VALUE;
         }
@@ -213,7 +213,13 @@
         memcpy(eheader->mData, keyBlob->getData(), keySize);
         memcpy(eheader->mData + keySize, valueBlob->getData(), valueSize);
 
-        byteOffset += align4(entrySize);
+        if (totalSize > entrySize) {
+            // We have padding bytes. Those will get written to storage, and contribute to the CRC,
+            // so make sure we zero-them to have reproducible results.
+            memset(eheader->mData + keySize + valueSize, 0, totalSize - entrySize);
+        }
+
+        byteOffset += totalSize;
     }
 
     return OK;
@@ -256,7 +262,8 @@
         size_t valueSize = eheader->mValueSize;
         size_t entrySize = sizeof(EntryHeader) + keySize + valueSize;
 
-        if (byteOffset + entrySize > size) {
+        size_t totalSize = align4(entrySize);
+        if (byteOffset + totalSize > size) {
             mCacheEntries.clear();
             ALOGE("unflatten: not enough room for cache entry headers");
             return BAD_VALUE;
@@ -265,7 +272,7 @@
         const uint8_t* data = eheader->mData;
         set(data, keySize, data + keySize, valueSize);
 
-        byteOffset += align4(entrySize);
+        byteOffset += totalSize;
     }
 
     return OK;
diff --git a/libutils/FileMap.cpp b/libutils/FileMap.cpp
index be4b14f..f8d6bda 100644
--- a/libutils/FileMap.cpp
+++ b/libutils/FileMap.cpp
@@ -77,7 +77,6 @@
     if (mFileMapping != INVALID_HANDLE_VALUE) {
         CloseHandle(mFileMapping);
     }
-    CloseHandle(mFileHandle);
 #endif
 }
 
diff --git a/libutils/NativeHandle.cpp b/libutils/NativeHandle.cpp
new file mode 100644
index 0000000..e4daca7
--- /dev/null
+++ b/libutils/NativeHandle.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2014 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 <utils/NativeHandle.h>
+#include <cutils/native_handle.h>
+
+namespace android {
+
+sp<NativeHandle> NativeHandle::create(
+        native_handle_t* handle, bool ownsHandle) {
+    return handle ? new NativeHandle(handle, ownsHandle) : NULL;
+}
+
+NativeHandle::NativeHandle(native_handle_t* handle, bool ownsHandle)
+:   mHandle(handle), mOwnsHandle(ownsHandle)
+{}
+
+NativeHandle::~NativeHandle() {
+    if (mOwnsHandle) {
+        native_handle_close(mHandle);
+        native_handle_delete(mHandle);
+    }
+}
+
+} // namespace android
diff --git a/libutils/ProcessCallStack.cpp b/libutils/ProcessCallStack.cpp
index f837bcb..db07e56 100644
--- a/libutils/ProcessCallStack.cpp
+++ b/libutils/ProcessCallStack.cpp
@@ -90,6 +90,11 @@
         ALOGE("%s: Failed to open %s", __FUNCTION__, path);
     }
 
+    if (procName == NULL) {
+        // Reading /proc/self/task/%d/comm failed due to a race
+        return String8::format("[err-unknown-tid-%d]", tid);
+    }
+
     // Strip ending newline
     strtok(procName, "\n");
 
diff --git a/libutils/String8.cpp b/libutils/String8.cpp
index 49340bb..9092cbc 100644
--- a/libutils/String8.cpp
+++ b/libutils/String8.cpp
@@ -408,6 +408,30 @@
     return p ? p-mString : -1;
 }
 
+bool String8::removeAll(const char* other) {
+    ssize_t index = find(other);
+    if (index < 0) return false;
+
+    char* buf = lockBuffer(size());
+    if (!buf) return false; // out of memory
+
+    size_t skip = strlen(other);
+    size_t len = size();
+    size_t tail = index;
+    while (size_t(index) < len) {
+        ssize_t next = find(other, index + skip);
+        if (next < 0) {
+            next = len;
+        }
+
+        memcpy(buf + tail, buf + index + skip, next - index - skip);
+        tail += next - index - skip;
+        index = next;
+    }
+    unlockBuffer(tail);
+    return true;
+}
+
 void String8::toLower()
 {
     toLower(0, size());
diff --git a/libutils/Threads.cpp b/libutils/Threads.cpp
index cc7fe89..b09d510 100644
--- a/libutils/Threads.cpp
+++ b/libutils/Threads.cpp
@@ -29,7 +29,7 @@
 # include <sched.h>
 # include <sys/resource.h>
 #ifdef HAVE_ANDROID_OS
-# include <bionic_pthread.h>
+# include <private/bionic_pthread.h>
 #endif
 #elif defined(HAVE_WIN32_THREADS)
 # include <windows.h>
diff --git a/libutils/Unicode.cpp b/libutils/Unicode.cpp
index fe8887d..378d2a7 100644
--- a/libutils/Unicode.cpp
+++ b/libutils/Unicode.cpp
@@ -342,7 +342,8 @@
     while (cur_utf16 < end_utf16) {
         char32_t utf32;
         // surrogate pairs
-        if ((*cur_utf16 & 0xFC00) == 0xD800) {
+        if((*cur_utf16 & 0xFC00) == 0xD800 && (cur_utf16 + 1) < end_utf16
+                && (*(cur_utf16 + 1) & 0xFC00) == 0xDC00) {
             utf32 = (*cur_utf16++ - 0xD800) << 10;
             utf32 |= *cur_utf16++ - 0xDC00;
             utf32 += 0x10000;
diff --git a/libziparchive/Android.mk b/libziparchive/Android.mk
index 705caa5..d23a94f 100644
--- a/libziparchive/Android.mk
+++ b/libziparchive/Android.mk
@@ -42,6 +42,9 @@
 LOCAL_STATIC_LIBRARIES := libz libutils
 LOCAL_MODULE:= libziparchive-host
 LOCAL_CFLAGS := -Werror
+ifneq ($(strip $(USE_MINGW)),)
+	LOCAL_CFLAGS += -mno-ms-bitfields
+endif
 LOCAL_MULTILIB := both
 include $(BUILD_HOST_STATIC_LIBRARY)
 
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 128bad4..87dac0e 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -287,7 +287,7 @@
  */
 struct ZipArchive {
   /* open Zip archive */
-  int fd;
+  const int fd;
 
   /* mapped central directory area */
   off64_t directory_offset;
@@ -304,6 +304,25 @@
    */
   uint32_t hash_table_size;
   ZipEntryName* hash_table;
+
+  ZipArchive(const int fd) :
+      fd(fd),
+      directory_offset(0),
+      directory_map(NULL),
+      num_entries(0),
+      hash_table_size(0),
+      hash_table(NULL) {}
+
+  ~ZipArchive() {
+    if (fd >= 0) {
+      close(fd);
+    }
+
+    if (directory_map != NULL) {
+      directory_map->release();
+    }
+    free(hash_table);
+  }
 };
 
 // Returns 0 on success and negative values on failure.
@@ -619,9 +638,15 @@
     const uint16_t file_name_length = cdr->file_name_length;
     const uint16_t extra_length = cdr->extra_field_length;
     const uint16_t comment_length = cdr->comment_length;
+    const char* file_name = reinterpret_cast<const char*>(ptr + sizeof(CentralDirectoryRecord));
+
+    /* check that file name doesn't contain \0 character */
+    if (memchr(file_name, 0, file_name_length) != NULL) {
+      ALOGW("Zip: entry name can't contain \\0 character");
+      goto bail;
+    }
 
     /* add the CDE filename to the hash table */
-    const char* file_name = reinterpret_cast<const char *>(ptr + sizeof(CentralDirectoryRecord));
     const int add_result = AddToHash(archive->hash_table,
         archive->hash_table_size, file_name, file_name_length);
     if (add_result) {
@@ -661,28 +686,20 @@
 
 int32_t OpenArchiveFd(int fd, const char* debug_file_name,
                       ZipArchiveHandle* handle) {
-  ZipArchive* archive = (ZipArchive*) malloc(sizeof(ZipArchive));
-  memset(archive, 0, sizeof(*archive));
+  ZipArchive* archive = new ZipArchive(fd);
   *handle = archive;
-
-  archive->fd = fd;
-
   return OpenArchiveInternal(archive, debug_file_name);
 }
 
 int32_t OpenArchive(const char* fileName, ZipArchiveHandle* handle) {
-  ZipArchive* archive = (ZipArchive*) malloc(sizeof(ZipArchive));
-  memset(archive, 0, sizeof(*archive));
+  const int fd = open(fileName, O_RDONLY | O_BINARY, 0);
+  ZipArchive* archive = new ZipArchive(fd);
   *handle = archive;
 
-  const int fd = open(fileName, O_RDONLY | O_BINARY, 0);
   if (fd < 0) {
     ALOGW("Unable to open '%s': %s", fileName, strerror(errno));
     return kIoError;
-  } else {
-    archive->fd = fd;
   }
-
   return OpenArchiveInternal(archive, fileName);
 }
 
@@ -692,16 +709,7 @@
 void CloseArchive(ZipArchiveHandle handle) {
   ZipArchive* archive = (ZipArchive*) handle;
   ALOGV("Closing archive %p", archive);
-
-  if (archive->fd >= 0) {
-    close(archive->fd);
-  }
-
-  if (archive->directory_map != NULL) {
-    archive->directory_map->release();
-  }
-  free(archive->hash_table);
-  free(archive);
+  delete archive;
 }
 
 static int32_t UpdateEntryFromDataDescriptor(int fd,
diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc
index 875b6de..813a87f 100644
--- a/libziparchive/zip_archive_test.cc
+++ b/libziparchive/zip_archive_test.cc
@@ -26,6 +26,7 @@
 
 static std::string test_data_dir;
 
+static const std::string kMissingZip = "missing.zip";
 static const std::string kValidZip = "valid.zip";
 
 static const uint8_t kATxtContents[] = {
@@ -58,6 +59,14 @@
   CloseArchive(handle);
 }
 
+TEST(ziparchive, OpenMissing) {
+  ZipArchiveHandle handle;
+  ASSERT_NE(0, OpenArchiveWrapper(kMissingZip, &handle));
+
+  // Confirm the file descriptor is not going to be mistaken for a valid one.
+  ASSERT_EQ(-1, GetFileDescriptor(handle));
+}
+
 TEST(ziparchive, Iteration) {
   ZipArchiveHandle handle;
   ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
diff --git a/lmkd/Android.mk b/lmkd/Android.mk
index 5d6d1d2..39081d6 100644
--- a/lmkd/Android.mk
+++ b/lmkd/Android.mk
@@ -2,8 +2,8 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES := lmkd.c
-LOCAL_STATIC_LIBRARIES := libcutils liblog libm libc
-LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_SHARED_LIBRARIES := liblog libm libc libprocessgroup
+LOCAL_CFLAGS := -Werror
 
 LOCAL_MODULE := lmkd
 
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index 376410b..a534a24 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -16,20 +16,27 @@
 
 #define LOG_TAG "lowmemorykiller"
 
+#include <arpa/inet.h>
 #include <errno.h>
 #include <signal.h>
-#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
-#include <unistd.h>
-#include <arpa/inet.h>
+#include <sys/cdefs.h>
 #include <sys/epoll.h>
 #include <sys/eventfd.h>
+#include <sys/mman.h>
 #include <sys/socket.h>
 #include <sys/types.h>
-#include <cutils/log.h>
+#include <unistd.h>
+
 #include <cutils/sockets.h>
+#include <log/log.h>
+#include <processgroup/processgroup.h>
+
+#ifndef __unused
+#define __unused __attribute__((__unused__))
+#endif
 
 #define MEMCG_SYSFS_PATH "/dev/memcg/"
 #define MEMPRESSURE_WATCH_LEVEL "medium"
@@ -75,6 +82,10 @@
 #define OOM_ADJUST_MIN (-16)
 #define OOM_ADJUST_MAX 15
 
+/* kernel OOM score values */
+#define OOM_SCORE_ADJ_MIN       (-1000)
+#define OOM_SCORE_ADJ_MAX       1000
+
 static int lowmem_adj[MAX_TARGETS];
 static int lowmem_minfree[MAX_TARGETS];
 static int lowmem_targets_size;
@@ -94,6 +105,7 @@
 struct proc {
     struct adjslot_list asl;
     int pid;
+    uid_t uid;
     int oomadj;
     struct proc *pidhash_next;
 };
@@ -116,6 +128,34 @@
 /* PAGE_SIZE / 1024 */
 static long page_k;
 
+static ssize_t read_all(int fd, char *buf, size_t max_len)
+{
+    ssize_t ret = 0;
+
+    while (max_len > 0) {
+        ssize_t r = read(fd, buf, max_len);
+        if (r == 0) {
+            break;
+        }
+        if (r == -1) {
+            return -1;
+        }
+        ret += r;
+        buf += r;
+        max_len -= r;
+    }
+
+    return ret;
+}
+
+static int lowmem_oom_adj_to_oom_score_adj(int oom_adj)
+{
+    if (oom_adj == OOM_ADJUST_MAX)
+        return OOM_SCORE_ADJ_MAX;
+    else
+        return (oom_adj * OOM_SCORE_ADJ_MAX) / -OOM_DISABLE;
+}
+
 static struct proc *pid_lookup(int pid) {
     struct proc *procp;
 
@@ -209,7 +249,7 @@
     close(fd);
 }
 
-static void cmd_procprio(int pid, int oomadj) {
+static void cmd_procprio(int pid, int uid, int oomadj) {
     struct proc *procp;
     char path[80];
     char val[20];
@@ -219,8 +259,8 @@
         return;
     }
 
-    snprintf(path, sizeof(path), "/proc/%d/oom_adj", pid);
-    snprintf(val, sizeof(val), "%d", oomadj);
+    snprintf(path, sizeof(path), "/proc/%d/oom_score_adj", pid);
+    snprintf(val, sizeof(val), "%d", lowmem_oom_adj_to_oom_score_adj(oomadj));
     writefilestring(path, val);
 
     if (use_inkernel_interface)
@@ -235,6 +275,7 @@
             }
 
             procp->pid = pid;
+            procp->uid = uid;
             procp->oomadj = oomadj;
             proc_insert(procp);
     } else {
@@ -245,8 +286,6 @@
 }
 
 static void cmd_procremove(int pid) {
-    struct proc *procp;
-
     if (use_inkernel_interface)
         return;
 
@@ -340,9 +379,9 @@
         cmd_target(targets, &ibuf[1]);
         break;
     case LMK_PROCPRIO:
-        if (nargs != 2)
+        if (nargs != 3)
             goto wronglen;
-        cmd_procprio(ntohl(ibuf[1]), ntohl(ibuf[2]));
+        cmd_procprio(ntohl(ibuf[1]), ntohl(ibuf[2]), ntohl(ibuf[3]));
         break;
     case LMK_PROCREMOVE:
         if (nargs != 1)
@@ -370,7 +409,7 @@
     }
 }
 
-static void ctrl_connect_handler(uint32_t events) {
+static void ctrl_connect_handler(uint32_t events __unused) {
     struct sockaddr addr;
     socklen_t alen;
     struct epoll_event epev;
@@ -402,17 +441,13 @@
 static int zoneinfo_parse_protection(char *cp) {
     int max = 0;
     int zoneval;
+    char *save_ptr;
 
-    if (*cp++ != '(')
-        return 0;
-
-    do {
+    for (cp = strtok_r(cp, "(), ", &save_ptr); cp; cp = strtok_r(NULL, "), ", &save_ptr)) {
         zoneval = strtol(cp, &cp, 0);
-        if ((*cp != ',') && (*cp != ')'))
-            return 0;
         if (zoneval > max)
             max = zoneval;
-    } while (cp = strtok(NULL, " "));
+    }
 
     return max;
 }
@@ -420,12 +455,13 @@
 static void zoneinfo_parse_line(char *line, struct sysmeminfo *mip) {
     char *cp = line;
     char *ap;
+    char *save_ptr;
 
-    cp = strtok(line, " ");
+    cp = strtok_r(line, " ", &save_ptr);
     if (!cp)
         return;
 
-    ap = strtok(NULL, " ");
+    ap = strtok_r(NULL, " ", &save_ptr);
     if (!ap)
         return;
 
@@ -442,57 +478,74 @@
 }
 
 static int zoneinfo_parse(struct sysmeminfo *mip) {
-    FILE *f;
-    char *cp;
-    char line[LINE_MAX];
+    int fd;
+    ssize_t size;
+    char buf[PAGE_SIZE];
+    char *save_ptr;
+    char *line;
 
     memset(mip, 0, sizeof(struct sysmeminfo));
-    f = fopen(ZONEINFO_PATH, "r");
-    if (!f) {
+
+    fd = open(ZONEINFO_PATH, O_RDONLY);
+    if (fd == -1) {
         ALOGE("%s open: errno=%d", ZONEINFO_PATH, errno);
         return -1;
     }
 
-    while (fgets(line, LINE_MAX, f))
+    size = read_all(fd, buf, sizeof(buf) - 1);
+    if (size < 0) {
+        ALOGE("%s read: errno=%d", ZONEINFO_PATH, errno);
+        close(fd);
+        return -1;
+    }
+    ALOG_ASSERT((size_t)size < sizeof(buf) - 1, "/proc/zoneinfo too large");
+    buf[size] = 0;
+
+    for (line = strtok_r(buf, "\n", &save_ptr); line; line = strtok_r(NULL, "\n", &save_ptr))
             zoneinfo_parse_line(line, mip);
 
-    fclose(f);
+    close(fd);
     return 0;
 }
 
 static int proc_get_size(int pid) {
     char path[PATH_MAX];
     char line[LINE_MAX];
-    FILE *f;
+    int fd;
     int rss = 0;
     int total;
+    ssize_t ret;
 
     snprintf(path, PATH_MAX, "/proc/%d/statm", pid);
-    f = fopen(path, "r");
-    if (!f)
+    fd = open(path, O_RDONLY);
+    if (fd == -1)
         return -1;
-    if (!fgets(line, LINE_MAX, f)) {
-        fclose(f);
+
+    ret = read_all(fd, line, sizeof(line) - 1);
+    if (ret < 0) {
+        close(fd);
         return -1;
     }
 
     sscanf(line, "%d %d ", &total, &rss);
-    fclose(f);
+    close(fd);
     return rss;
 }
 
 static char *proc_get_name(int pid) {
     char path[PATH_MAX];
     static char line[LINE_MAX];
-    FILE *f;
+    int fd;
     char *cp;
+    ssize_t ret;
 
     snprintf(path, PATH_MAX, "/proc/%d/cmdline", pid);
-    f = fopen(path, "r");
-    if (!f)
+    fd = open(path, O_RDONLY);
+    if (fd == -1)
         return NULL;
-    if (!fgets(line, LINE_MAX, f)) {
-        fclose(f);
+    ret = read_all(fd, line, sizeof(line) - 1);
+    close(fd);
+    if (ret < 0) {
         return NULL;
     }
 
@@ -507,29 +560,57 @@
     return (struct proc *)adjslot_tail(&procadjslot_list[ADJTOSLOT(oomadj)]);
 }
 
-static void mp_event(uint32_t events) {
+/* Kill one process specified by procp.  Returns the size of the process killed */
+static int kill_one_process(struct proc *procp, int other_free, int other_file,
+        int minfree, int min_score_adj, bool first)
+{
+    int pid = procp->pid;
+    uid_t uid = procp->uid;
+    char *taskname;
+    int tasksize;
+    int r;
+
+    taskname = proc_get_name(pid);
+    if (!taskname) {
+        pid_remove(pid);
+        return -1;
+    }
+
+    tasksize = proc_get_size(pid);
+    if (tasksize <= 0) {
+        pid_remove(pid);
+        return -1;
+    }
+
+    ALOGI("Killing '%s' (%d), uid %d, adj %d\n"
+          "   to free %ldkB because cache %s%ldkB is below limit %ldkB for oom_adj %d\n"
+          "   Free memory is %s%ldkB %s reserved",
+          taskname, pid, uid, procp->oomadj, tasksize * page_k,
+          first ? "" : "~", other_file * page_k, minfree * page_k, min_score_adj,
+          first ? "" : "~", other_free * page_k, other_free >= 0 ? "above" : "below");
+    r = kill(pid, SIGKILL);
+    killProcessGroup(uid, pid, SIGKILL);
+    pid_remove(pid);
+
+    if (r) {
+        ALOGE("kill(%d): errno=%d", procp->pid, errno);
+        return -1;
+    } else {
+        return tasksize;
+    }
+}
+
+/*
+ * Find a process to kill based on the current (possibly estimated) free memory
+ * and cached memory sizes.  Returns the size of the killed processes.
+ */
+static int find_and_kill_process(int other_free, int other_file, bool first)
+{
     int i;
-    int ret;
-    unsigned long long evcount;
-    struct sysmeminfo mi;
-    int other_free;
-    int other_file;
-    int minfree = 0;
+    int r;
     int min_score_adj = OOM_ADJUST_MAX + 1;
-
-    ret = read(mpevfd, &evcount, sizeof(evcount));
-    if (ret < 0)
-        ALOGE("Error reading memory pressure event fd; errno=%d",
-              errno);
-
-    if (time(NULL) - kill_lasttime < KILL_TIMEOUT)
-        return;
-
-    if (zoneinfo_parse(&mi) < 0)
-        return;
-
-    other_free = mi.nr_free_pages - mi.totalreserve_pages;
-    other_file = mi.nr_file_pages - mi.nr_shmem;
+    int minfree = 0;
+    int killed_size = 0;
 
     for (i = 0; i < lowmem_targets_size; i++) {
         minfree = lowmem_minfree[i];
@@ -540,50 +621,61 @@
     }
 
     if (min_score_adj == OOM_ADJUST_MAX + 1)
-        return;
+        return 0;
 
     for (i = OOM_ADJUST_MAX; i >= min_score_adj; i--) {
         struct proc *procp;
 
-    retry:
+retry:
         procp = proc_adj_lru(i);
 
         if (procp) {
-            int pid = procp->pid;
-            char *taskname;
-            int tasksize;
-            int r;
-
-            taskname = proc_get_name(pid);
-            if (!taskname) {
-                pid_remove(pid);
-                goto retry;
-            }
-
-            tasksize = proc_get_size(pid);
-            if (tasksize < 0) {
-                pid_remove(pid);
-                goto retry;
-            }
-
-            ALOGI("Killing '%s' (%d), adj %d\n"
-                  "   to free %ldkB because cache %ldkB is below limit %ldkB for oom_adj %d\n"
-                  "   Free memory is %ldkB %s reserved",
-                  taskname, pid, procp->oomadj, tasksize * page_k,
-                  other_file * page_k, minfree * page_k, min_score_adj,
-                  other_free * page_k, other_free >= 0 ? "above" : "below");
-            r = kill(pid, SIGKILL);
-            pid_remove(pid);
-
-            if (r) {
-                ALOGE("kill(%d): errno=%d", procp->pid, errno);
+            killed_size = kill_one_process(procp, other_free, other_file, minfree, min_score_adj, first);
+            if (killed_size < 0) {
                 goto retry;
             } else {
-                time(&kill_lasttime);
-                break;
+                return killed_size;
             }
         }
     }
+
+    return 0;
+}
+
+static void mp_event(uint32_t events __unused) {
+    int i;
+    int ret;
+    unsigned long long evcount;
+    struct sysmeminfo mi;
+    int other_free;
+    int other_file;
+    int killed_size;
+    bool first = true;
+
+    ret = read(mpevfd, &evcount, sizeof(evcount));
+    if (ret < 0)
+        ALOGE("Error reading memory pressure event fd; errno=%d",
+              errno);
+
+    if (time(NULL) - kill_lasttime < KILL_TIMEOUT)
+        return;
+
+    while (zoneinfo_parse(&mi) < 0) {
+        // Failed to read /proc/zoneinfo, assume ENOMEM and kill something
+        find_and_kill_process(0, 0, true);
+    }
+
+    other_free = mi.nr_free_pages - mi.totalreserve_pages;
+    other_file = mi.nr_file_pages - mi.nr_shmem;
+
+    do {
+        killed_size = find_and_kill_process(other_free, other_file, first);
+        if (killed_size > 0) {
+            first = false;
+            other_free += killed_size;
+            other_file += killed_size;
+        }
+    } while (killed_size > 0);
 }
 
 static int init_mp(char *levelstr, void *event_handler)
@@ -726,7 +818,13 @@
     }
 }
 
-int main(int argc, char **argv) {
+int main(int argc __unused, char **argv __unused) {
+    struct sched_param param = {
+            .sched_priority = 1,
+    };
+
+    mlockall(MCL_FUTURE);
+    sched_setscheduler(0, SCHED_FIFO, &param);
     if (!init())
         mainloop();
 
diff --git a/logcat/event.logtags b/logcat/event.logtags
index a325692..1b5c6f4 100644
--- a/logcat/event.logtags
+++ b/logcat/event.logtags
@@ -134,5 +134,7 @@
 # libcore failure logging
 90100 exp_det_cert_pin_failure (certs|4)
 
+1397638484 snet_event_log (subtag|3) (uid|1) (message|3)
+
 # NOTE - the range 1000000-2000000 is reserved for partners and others who
 # want to define their own log tags without conflicting with the core platform.
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 7c6af42..858e56c 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -224,7 +224,10 @@
                     "  -c              clear (flush) the entire log and exit\n"
                     "  -d              dump the log and then exit (don't block)\n"
                     "  -t <count>      print only the most recent <count> lines (implies -d)\n"
+                    "  -t '<time>'     print most recent lines since specified time (implies -d)\n"
                     "  -T <count>      print only the most recent <count> lines (does not imply -d)\n"
+                    "  -T '<time>'     print most recent lines since specified time (not imply -d)\n"
+                    "                  count is pure numerical, time is 'MM-DD hh:mm:ss.mmm'\n"
                     "  -g              get the size of the log's ring buffer and exit\n"
                     "  -b <buffer>     Request alternate ring buffer, 'main', 'system', 'radio',\n"
                     "                  'events', 'crash' or 'all'. Multiple -b parameters are\n"
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index 9b316d1..85756d5 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -284,21 +284,21 @@
 
     while (fgets(buffer, sizeof(buffer), fp)) {
         int size, consumed, max, payload;
-        char size_mult, consumed_mult;
+        char size_mult[2], consumed_mult[2];
         long full_size, full_consumed;
 
         size = consumed = max = payload = 0;
         // NB: crash log can be very small, not hit a Kb of consumed space
         //     doubly lucky we are not including it.
-        if (6 != sscanf(buffer, "%*s ring buffer is %d%cb (%d%cb consumed),"
+        if (6 != sscanf(buffer, "%*s ring buffer is %d%2s (%d%2s consumed),"
                                 " max entry is %db, max payload is %db",
-                                &size, &size_mult, &consumed, &consumed_mult,
+                                &size, size_mult, &consumed, consumed_mult,
                                 &max, &payload)) {
             fprintf(stderr, "WARNING: Parse error: %s", buffer);
             continue;
         }
         full_size = size;
-        switch(size_mult) {
+        switch(size_mult[0]) {
         case 'G':
             full_size *= 1024;
             /* FALLTHRU */
@@ -307,10 +307,12 @@
             /* FALLTHRU */
         case 'K':
             full_size *= 1024;
+            /* FALLTHRU */
+        case 'b':
             break;
         }
         full_consumed = consumed;
-        switch(consumed_mult) {
+        switch(consumed_mult[0]) {
         case 'G':
             full_consumed *= 1024;
             /* FALLTHRU */
@@ -319,6 +321,8 @@
             /* FALLTHRU */
         case 'K':
             full_consumed *= 1024;
+            /* FALLTHRU */
+        case 'b':
             break;
         }
         EXPECT_GT((full_size * 9) / 4, full_consumed);
@@ -477,6 +481,45 @@
     EXPECT_EQ(1, signals);
 }
 
+TEST(logcat, logrotate) {
+    static const char form[] = "/data/local/tmp/logcat.logrotate.XXXXXX";
+    char buf[sizeof(form)];
+    ASSERT_TRUE(NULL != mkdtemp(strcpy(buf, form)));
+
+    static const char comm[] = "logcat -b radio -b events -b system -b main"
+                                     " -d -f %s/log.txt -n 7 -r 1";
+    char command[sizeof(buf) + sizeof(comm)];
+    sprintf(command, comm, buf);
+
+    int ret;
+    EXPECT_FALSE((ret = system(command)));
+    if (!ret) {
+        sprintf(command, "ls -s %s 2>/dev/null", buf);
+
+        FILE *fp;
+        EXPECT_TRUE(NULL != (fp = popen(command, "r")));
+        if (fp) {
+            char buffer[5120];
+            int count = 0;
+
+            while (fgets(buffer, sizeof(buffer), fp)) {
+                static const char match[] = "4 log.txt";
+                static const char total[] = "total ";
+
+                if (!strncmp(buffer, match, sizeof(match) - 1)) {
+                    ++count;
+                } else if (strncmp(buffer, total, sizeof(total) - 1)) {
+                    fprintf(stderr, "WARNING: Parse error: %s", buffer);
+                }
+            }
+            pclose(fp);
+            EXPECT_TRUE(count == 7 || count == 8);
+        }
+    }
+    sprintf(command, "rm -rf %s", buf);
+    EXPECT_FALSE(system(command));
+}
+
 static void caught_blocking_clear(int /*signum*/)
 {
     unsigned long long v = 0xDEADBEEFA55C0000ULL;
diff --git a/logd/LogReader.cpp b/logd/LogReader.cpp
index 8458c19..26df087 100644
--- a/logd/LogReader.cpp
+++ b/logd/LogReader.cpp
@@ -92,6 +92,11 @@
 
     bool nonBlock = false;
     if (strncmp(buffer, "dumpAndClose", 12) == 0) {
+        // Allow writer to get some cycles, and wait for pending notifications
+        sched_yield();
+        LogTimeEntry::lock();
+        LogTimeEntry::unlock();
+        sched_yield();
         nonBlock = true;
     }
 
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index 81c9bab..a2f27c6 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -524,7 +524,7 @@
     short spaces = 2;
 
     log_id_for_each(i) {
-        if (!logMask & (1 << i)) {
+        if (!(logMask & (1 << i))) {
             continue;
         }
         oldLength = string.length();
diff --git a/logd/LogTimes.cpp b/logd/LogTimes.cpp
index e7e3ec2..ea4e8c8 100644
--- a/logd/LogTimes.cpp
+++ b/logd/LogTimes.cpp
@@ -33,7 +33,6 @@
         , mRelease(false)
         , mError(false)
         , threadRunning(false)
-        , threadTriggered(true)
         , mReader(reader)
         , mLogMask(logMask)
         , mPid(pid)
@@ -45,7 +44,9 @@
         , mStart(start)
         , mNonBlock(nonBlock)
         , mEnd(CLOCK_MONOTONIC)
-{ }
+{
+        pthread_cond_init(&threadTriggeredCondition, NULL);
+}
 
 void LogTimeEntry::startReader_Locked(void) {
     pthread_attr_t attr;
@@ -74,7 +75,6 @@
 
     lock();
 
-    me->threadRunning = false;
     if (me->mNonBlock) {
         me->error_Locked();
     }
@@ -103,6 +103,7 @@
         client->decRef();
     }
 
+    me->threadRunning = false;
     me->decRef_Locked();
 
     unlock();
@@ -118,7 +119,7 @@
     SocketClient *client = me->mClient;
     if (!client) {
         me->error();
-        pthread_exit(NULL);
+        return NULL;
     }
 
     LogBuffer &logbuf = me->mReader.logbuf();
@@ -127,12 +128,7 @@
 
     lock();
 
-    me->threadTriggered = true;
-
-    while(me->threadTriggered && !me->isError_Locked()) {
-
-        me->threadTriggered = false;
-
+    while (me->threadRunning && !me->isError_Locked()) {
         log_time start = me->mStart;
 
         unlock();
@@ -142,24 +138,21 @@
         }
         start = logbuf.flushTo(client, start, privileged, FilterSecondPass, me);
 
+        lock();
+
         if (start == LogBufferElement::FLUSH_ERROR) {
-            me->error();
+            me->error_Locked();
         }
 
-        if (me->mNonBlock) {
-            lock();
+        if (me->mNonBlock || !me->threadRunning || me->isError_Locked()) {
             break;
         }
 
-        sched_yield();
-
-        lock();
+        pthread_cond_wait(&me->threadTriggeredCondition, &timesLock);
     }
 
     unlock();
 
-    pthread_exit(NULL);
-
     pthread_cleanup_pop(true);
 
     return NULL;
diff --git a/logd/LogTimes.h b/logd/LogTimes.h
index beaf646..0bfa7a2 100644
--- a/logd/LogTimes.h
+++ b/logd/LogTimes.h
@@ -31,7 +31,7 @@
     bool mRelease;
     bool mError;
     bool threadRunning;
-    bool threadTriggered;
+    pthread_cond_t threadTriggeredCondition;
     pthread_t mThread;
     LogReader &mReader;
     static void *threadStart(void *me);
@@ -63,12 +63,16 @@
     bool runningReader_Locked(void) const {
         return threadRunning || mRelease || mError || mNonBlock;
     }
-    void triggerReader_Locked(void) { threadTriggered = true; }
+    void triggerReader_Locked(void) {
+        pthread_cond_signal(&threadTriggeredCondition);
+    }
+
     void triggerSkip_Locked(unsigned int skip) { skipAhead = skip; }
 
     // Called after LogTimeEntry removed from list, lock implicitly held
     void release_Locked(void) {
         mRelease = true;
+        pthread_cond_signal(&threadTriggeredCondition);
         if (mRefCount || threadRunning) {
             return;
         }
@@ -78,7 +82,7 @@
 
     // Called to mark socket in jeopardy
     void error_Locked(void) { mError = true; }
-    void error(void) { lock(); mError = true; unlock(); }
+    void error(void) { lock(); error_Locked(); unlock(); }
 
     bool isError_Locked(void) const { return mRelease || mError; }
 
diff --git a/logd/main.cpp b/logd/main.cpp
index ece5a3a..1e1a718 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -22,12 +22,11 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/capability.h>
+#include <sys/prctl.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
 
-#include <linux/prctl.h>
-
 #include <cutils/properties.h>
 
 #include "private/android_filesystem_config.h"
diff --git a/logd/tests/logd_test.cpp b/logd/tests/logd_test.cpp
index 957fdb5..4bea4be 100644
--- a/logd/tests/logd_test.cpp
+++ b/logd/tests/logd_test.cpp
@@ -503,13 +503,11 @@
             (user_logger_content)     ? yes : no,
             (kernel_logger_available) ? yes : no,
             (kernel_logger_content)   ? yes : no,
-            (user_logger_available && kernel_logger_available) ? "WARNING" : "ok",
+            (user_logger_available && kernel_logger_available) ? "ERROR" : "ok",
             (user_logger_content && kernel_logger_content) ? "ERROR" : "ok");
 
-    if (user_logger_available && kernel_logger_available) {
-        printf("WARNING: kernel & user logger; both consuming resources!!!\n");
-    }
-
+    EXPECT_EQ(0, user_logger_available && kernel_logger_available);
+    EXPECT_EQ(0, !user_logger_available && !kernel_logger_available);
     EXPECT_EQ(0, user_logger_content && kernel_logger_content);
     EXPECT_EQ(0, !user_logger_content && !kernel_logger_content);
 }
diff --git a/logwrapper/logwrap.c b/logwrapper/logwrap.c
index d47c9b5..3a6276e 100644
--- a/logwrapper/logwrap.c
+++ b/logwrapper/logwrap.c
@@ -477,7 +477,6 @@
     pid_t pid;
     int parent_ptty;
     int child_ptty;
-    char *child_devname = NULL;
     struct sigaction intact;
     struct sigaction quitact;
     sigset_t blockset;
@@ -498,8 +497,9 @@
         goto err_open;
     }
 
+    char child_devname[64];
     if (grantpt(parent_ptty) || unlockpt(parent_ptty) ||
-            ((child_devname = (char*)ptsname(parent_ptty)) == 0)) {
+            ptsname_r(parent_ptty, child_devname, sizeof(child_devname)) != 0) {
         ERROR("Problem with /dev/ptmx\n");
         rc = -1;
         goto err_ptty;
diff --git a/netcfg/netcfg.c b/netcfg/netcfg.c
index 2308f37..4e83ba4 100644
--- a/netcfg/netcfg.c
+++ b/netcfg/netcfg.c
@@ -102,7 +102,6 @@
     { "dhcp",   1, do_dhcp },
     { "up",     1, ifc_up },
     { "down",   1, ifc_down },
-    { "flhosts",  1, ifc_remove_host_routes },
     { "deldefault", 1, ifc_remove_default_route },
     { "hwaddr", 2, set_hwaddr },
     { 0, 0, 0 },
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index aca08bf..3ecb1db 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -31,7 +31,7 @@
 include $(BUILD_SYSTEM)/base_rules.mk
 
 # Regenerate init.environ.rc if PRODUCT_BOOTCLASSPATH has changed.
-bcp_md5 := $(word 1, $(shell echo $(PRODUCT_BOOTCLASSPATH) | $(MD5SUM)))
+bcp_md5 := $(word 1, $(shell echo $(PRODUCT_BOOTCLASSPATH) $(PRODUCT_SYSTEM_SERVER_CLASSPATH) | $(MD5SUM)))
 bcp_dep := $(intermediates)/$(bcp_md5).bcp.dep
 $(bcp_dep) :
 	$(hide) mkdir -p $(dir $@) && rm -rf $(dir $@)*.bcp.dep && touch $@
@@ -40,6 +40,7 @@
 	@echo "Generate: $< -> $@"
 	@mkdir -p $(dir $@)
 	$(hide) sed -e 's?%BOOTCLASSPATH%?$(PRODUCT_BOOTCLASSPATH)?g' $< >$@
+	$(hide) sed -i -e 's?%SYSTEMSERVERCLASSPATH%?$(PRODUCT_SYSTEM_SERVER_CLASSPATH)?g' $@
 
 bcp_md5 :=
 bcp_dep :=
diff --git a/rootdir/init.environ.rc.in b/rootdir/init.environ.rc.in
index 1f964e3..67222d7 100644
--- a/rootdir/init.environ.rc.in
+++ b/rootdir/init.environ.rc.in
@@ -9,4 +9,5 @@
     export ASEC_MOUNTPOINT /mnt/asec
     export LOOP_MOUNTPOINT /mnt/obb
     export BOOTCLASSPATH %BOOTCLASSPATH%
+    export SYSTEMSERVERCLASSPATH %SYSTEMSERVERCLASSPATH%
     export LD_PRELOAD libsigchain.so
diff --git a/rootdir/init.rc b/rootdir/init.rc
index b59e31f..8ba7c10 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -12,7 +12,7 @@
 
 on early-init
     # Set init and its forked children's oom_adj.
-    write /proc/1/oom_adj -16
+    write /proc/1/oom_score_adj -1000
 
     # Apply strict SELinux checking of PROT_EXEC on mmap/mprotect calls.
     write /sys/fs/selinux/checkreqprot 0
@@ -168,6 +168,10 @@
 on load_all_props_action
     load_all_props
 
+# Indicate to fw loaders that the relevant mounts are up.
+on firmware_mounts_complete
+    rm /dev/.booting
+
 # Mount filesystems and start core system services.
 on late-init
     trigger early-fs
@@ -180,9 +184,13 @@
     # issued fs triggers have completed.
     trigger load_all_props_action
 
+    # Remove a file to wake up anything waiting for firmware.
+    trigger firmware_mounts_complete
+
     trigger early-boot
     trigger boot
 
+
 on post-fs
     # once everything is setup, no need to modify /
     mount rootfs rootfs / ro remount
@@ -263,6 +271,7 @@
     mkdir /data/misc/wifi 0770 wifi wifi
     mkdir /data/misc/wifi/sockets 0770 wifi wifi
     mkdir /data/misc/wifi/wpa_supplicant 0770 wifi wifi
+    mkdir /data/misc/ethernet 0770 system system
     mkdir /data/misc/dhcp 0770 dhcp dhcp
     mkdir /data/misc/user 0771 root root
     # give system access to wpa_supplicant.conf for backup and restore
@@ -281,7 +290,7 @@
     mkdir /data/property 0700 root root
 
     # create dalvik-cache, so as to enforce our permissions
-    mkdir /data/dalvik-cache 0771 system system
+    mkdir /data/dalvik-cache 0771 root root
     mkdir /data/dalvik-cache/profiles 0711 system system
 
     # create resource-cache and double-check the perms
@@ -333,9 +342,9 @@
     write /proc/sys/vm/overcommit_memory 1
     write /proc/sys/vm/min_free_order_shift 4
     chown root system /sys/module/lowmemorykiller/parameters/adj
-    chmod 0664 /sys/module/lowmemorykiller/parameters/adj
+    chmod 0220 /sys/module/lowmemorykiller/parameters/adj
     chown root system /sys/module/lowmemorykiller/parameters/minfree
-    chmod 0664 /sys/module/lowmemorykiller/parameters/minfree
+    chmod 0220 /sys/module/lowmemorykiller/parameters/minfree
 
     # Tweak background writeout
     write /proc/sys/vm/dirty_expire_centisecs 200
@@ -405,30 +414,22 @@
     chown system system /sys/kernel/ipv4/tcp_rmem_max
     chown root radio /proc/cmdline
 
-    # Define TCP buffer sizes for various networks
-    #   ReadMin, ReadInitial, ReadMax, WriteMin, WriteInitial, WriteMax,
-    setprop net.tcp.buffersize.default  4096,87380,110208,4096,16384,110208
-    setprop net.tcp.buffersize.wifi     524288,1048576,2097152,262144,524288,1048576
-    setprop net.tcp.buffersize.ethernet 524288,1048576,3145728,524288,1048576,2097152
-    setprop net.tcp.buffersize.lte      524288,1048576,2097152,262144,524288,1048576
-    setprop net.tcp.buffersize.umts     58254,349525,1048576,58254,349525,1048576
-    setprop net.tcp.buffersize.hspa     40778,244668,734003,16777,100663,301990
-    setprop net.tcp.buffersize.hsupa    40778,244668,734003,16777,100663,301990
-    setprop net.tcp.buffersize.hsdpa    61167,367002,1101005,8738,52429,262114
-    setprop net.tcp.buffersize.hspap    122334,734003,2202010,32040,192239,576717
-    setprop net.tcp.buffersize.edge     4093,26280,70800,4096,16384,70800
-    setprop net.tcp.buffersize.gprs     4092,8760,48000,4096,8760,48000
-    setprop net.tcp.buffersize.evdo     4094,87380,262144,4096,16384,262144
-
     # Define default initial receive window size in segments.
     setprop net.tcp.default_init_rwnd 60
 
     class_start core
-    class_start main
 
 on nonencrypted
+    class_start main
     class_start late_start
 
+on property:vold.decrypt=trigger_default_encryption
+    start defaultcrypto
+
+on property:vold.decrypt=trigger_encryption
+    start surfaceflinger
+    start encrypt
+
 on property:sys.init_log_level=*
     loglevel ${sys.init_log_level}
 
@@ -488,11 +489,6 @@
     critical
     seclabel u:r:healthd:s0
 
-service healthd-charger /sbin/healthd -n
-    class charger
-    critical
-    seclabel u:r:healthd:s0
-
 service console /system/bin/sh
     class core
     console
@@ -557,7 +553,7 @@
     group radio cache inet misc audio log
 
 service surfaceflinger /system/bin/surfaceflinger
-    class main
+    class core
     user system
     group graphics drmrpc
     onrestart restart zygote
@@ -573,10 +569,24 @@
     group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm
     ioprio rt 4
 
+# One shot invocation to deal with encrypted volume.
+service defaultcrypto /system/bin/vdc --wait cryptfs mountdefaultencrypted
+    disabled
+    oneshot
+    # vold will set vold.decrypt to trigger_restart_framework (default
+    # encryption) or trigger_restart_min_framework (other encryption)
+
+# One shot invocation to encrypt unencrypted volumes
+service encrypt /system/bin/vdc --wait cryptfs enablecrypto inplace default
+    disabled
+    oneshot
+    # vold will set vold.decrypt to trigger_restart_framework (default
+    # encryption)
+
 service bootanim /system/bin/bootanimation
-    class main
+    class core
     user graphics
-    group graphics
+    group graphics audio
     disabled
     oneshot
 
@@ -584,8 +594,9 @@
     class main
     socket installd stream 600 system system
 
-service flash_recovery /system/etc/install-recovery.sh
+service flash_recovery /system/bin/install-recovery.sh
     class main
+    seclabel u:r:install_recovery:s0
     oneshot
 
 service racoon /system/bin/racoon
@@ -622,3 +633,8 @@
     socket mdnsd stream 0660 mdnsr inet
     disabled
     oneshot
+
+service pre-recovery /system/bin/uncrypt
+    class main
+    disabled
+    oneshot
diff --git a/rootdir/init.trace.rc b/rootdir/init.trace.rc
index 50944e6..cd8d350 100644
--- a/rootdir/init.trace.rc
+++ b/rootdir/init.trace.rc
@@ -1,6 +1,6 @@
 ## Permissions to allow system-wide tracing to the kernel trace buffer.
 ##
-on boot
+on early-boot
 
 # Allow writing to the kernel trace log.
     chmod 0222 /sys/kernel/debug/tracing/trace_marker
diff --git a/rootdir/init.usb.rc b/rootdir/init.usb.rc
index 15467cc..e290ca4 100644
--- a/rootdir/init.usb.rc
+++ b/rootdir/init.usb.rc
@@ -17,12 +17,12 @@
     setprop sys.usb.state ${sys.usb.config}
 
 # adb only USB configuration
-# This should only be used during device bringup
-# and as a fallback if the USB manager fails to set a standard configuration
+# This is the fallback configuration if the
+# USB manager fails to set a standard configuration
 on property:sys.usb.config=adb
     write /sys/class/android_usb/android0/enable 0
     write /sys/class/android_usb/android0/idVendor 18d1
-    write /sys/class/android_usb/android0/idProduct D002
+    write /sys/class/android_usb/android0/idProduct 4EE7
     write /sys/class/android_usb/android0/functions ${sys.usb.config}
     write /sys/class/android_usb/android0/enable 1
     start adbd
diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c
index 844ca65..7bf6394 100644
--- a/sdcard/sdcard.c
+++ b/sdcard/sdcard.c
@@ -20,6 +20,7 @@
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <inttypes.h>
 #include <limits.h>
 #include <linux/fuse.h>
 #include <pthread.h>
@@ -142,6 +143,8 @@
     PERM_ANDROID_DATA,
     /* This node is "/Android/obb" */
     PERM_ANDROID_OBB,
+    /* This node is "/Android/media" */
+    PERM_ANDROID_MEDIA,
     /* This node is "/Android/user" */
     PERM_ANDROID_USER,
 } perm_t;
@@ -478,6 +481,10 @@
             /* Single OBB directory is always shared */
             node->graft_path = fuse->obbpath;
             node->graft_pathlen = strlen(fuse->obbpath);
+        } else if (!strcasecmp(node->name, "media")) {
+            /* App-specific directories inside; let anyone traverse */
+            node->perm = PERM_ANDROID_MEDIA;
+            node->mode = 0771;
         } else if (!strcasecmp(node->name, "user")) {
             /* User directories must only be accessible to system, protected
              * by sdcard_all. Zygote will bind mount the appropriate user-
@@ -489,6 +496,7 @@
         break;
     case PERM_ANDROID_DATA:
     case PERM_ANDROID_OBB:
+    case PERM_ANDROID_MEDIA:
         appid = (appid_t) (uintptr_t) hashmapGet(fuse->package_to_appid, node->name);
         if (appid != 0) {
             node->uid = multiuser_get_uid(parent->userid, appid);
@@ -821,7 +829,7 @@
     pthread_mutex_lock(&fuse->lock);
     parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
             parent_path, sizeof(parent_path));
-    TRACE("[%d] LOOKUP %s @ %llx (%s)\n", handler->token, name, hdr->nodeid,
+    TRACE("[%d] LOOKUP %s @ %"PRIx64" (%s)\n", handler->token, name, hdr->nodeid,
         parent_node ? parent_node->name : "?");
     pthread_mutex_unlock(&fuse->lock);
 
@@ -843,7 +851,7 @@
 
     pthread_mutex_lock(&fuse->lock);
     node = lookup_node_by_id_locked(fuse, hdr->nodeid);
-    TRACE("[%d] FORGET #%lld @ %llx (%s)\n", handler->token, req->nlookup,
+    TRACE("[%d] FORGET #%"PRIu64" @ %"PRIx64" (%s)\n", handler->token, req->nlookup,
             hdr->nodeid, node ? node->name : "?");
     if (node) {
         __u64 n = req->nlookup;
@@ -863,7 +871,7 @@
 
     pthread_mutex_lock(&fuse->lock);
     node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
-    TRACE("[%d] GETATTR flags=%x fh=%llx @ %llx (%s)\n", handler->token,
+    TRACE("[%d] GETATTR flags=%x fh=%"PRIx64" @ %"PRIx64" (%s)\n", handler->token,
             req->getattr_flags, req->fh, hdr->nodeid, node ? node->name : "?");
     pthread_mutex_unlock(&fuse->lock);
 
@@ -888,7 +896,7 @@
     pthread_mutex_lock(&fuse->lock);
     has_rw = get_caller_has_rw_locked(fuse, hdr);
     node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
-    TRACE("[%d] SETATTR fh=%llx valid=%x @ %llx (%s)\n", handler->token,
+    TRACE("[%d] SETATTR fh=%"PRIx64" valid=%x @ %"PRIx64" (%s)\n", handler->token,
             req->fh, req->valid, hdr->nodeid, node ? node->name : "?");
     pthread_mutex_unlock(&fuse->lock);
 
@@ -902,7 +910,7 @@
     /* XXX: incomplete implementation on purpose.
      * chmod/chown should NEVER be implemented.*/
 
-    if ((req->valid & FATTR_SIZE) && truncate(path, req->size) < 0) {
+    if ((req->valid & FATTR_SIZE) && truncate64(path, req->size) < 0) {
         return -errno;
     }
 
@@ -953,7 +961,7 @@
     has_rw = get_caller_has_rw_locked(fuse, hdr);
     parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
             parent_path, sizeof(parent_path));
-    TRACE("[%d] MKNOD %s 0%o @ %llx (%s)\n", handler->token,
+    TRACE("[%d] MKNOD %s 0%o @ %"PRIx64" (%s)\n", handler->token,
             name, req->mode, hdr->nodeid, parent_node ? parent_node->name : "?");
     pthread_mutex_unlock(&fuse->lock);
 
@@ -984,7 +992,7 @@
     has_rw = get_caller_has_rw_locked(fuse, hdr);
     parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
             parent_path, sizeof(parent_path));
-    TRACE("[%d] MKDIR %s 0%o @ %llx (%s)\n", handler->token,
+    TRACE("[%d] MKDIR %s 0%o @ %"PRIx64" (%s)\n", handler->token,
             name, req->mode, hdr->nodeid, parent_node ? parent_node->name : "?");
     pthread_mutex_unlock(&fuse->lock);
 
@@ -1033,7 +1041,7 @@
     has_rw = get_caller_has_rw_locked(fuse, hdr);
     parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
             parent_path, sizeof(parent_path));
-    TRACE("[%d] UNLINK %s @ %llx (%s)\n", handler->token,
+    TRACE("[%d] UNLINK %s @ %"PRIx64" (%s)\n", handler->token,
             name, hdr->nodeid, parent_node ? parent_node->name : "?");
     pthread_mutex_unlock(&fuse->lock);
 
@@ -1062,7 +1070,7 @@
     has_rw = get_caller_has_rw_locked(fuse, hdr);
     parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
             parent_path, sizeof(parent_path));
-    TRACE("[%d] RMDIR %s @ %llx (%s)\n", handler->token,
+    TRACE("[%d] RMDIR %s @ %"PRIx64" (%s)\n", handler->token,
             name, hdr->nodeid, parent_node ? parent_node->name : "?");
     pthread_mutex_unlock(&fuse->lock);
 
@@ -1100,7 +1108,7 @@
             old_parent_path, sizeof(old_parent_path));
     new_parent_node = lookup_node_and_path_by_id_locked(fuse, req->newdir,
             new_parent_path, sizeof(new_parent_path));
-    TRACE("[%d] RENAME %s->%s @ %llx (%s) -> %llx (%s)\n", handler->token,
+    TRACE("[%d] RENAME %s->%s @ %"PRIx64" (%s) -> %"PRIx64" (%s)\n", handler->token,
             old_name, new_name,
             hdr->nodeid, old_parent_node ? old_parent_node->name : "?",
             req->newdir, new_parent_node ? new_parent_node->name : "?");
@@ -1184,7 +1192,7 @@
     pthread_mutex_lock(&fuse->lock);
     has_rw = get_caller_has_rw_locked(fuse, hdr);
     node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
-    TRACE("[%d] OPEN 0%o @ %llx (%s)\n", handler->token,
+    TRACE("[%d] OPEN 0%o @ %"PRIx64" (%s)\n", handler->token,
             req->flags, hdr->nodeid, node ? node->name : "?");
     pthread_mutex_unlock(&fuse->lock);
 
@@ -1226,8 +1234,8 @@
      * overlaps the request buffer and will clobber data in the request.  This
      * saves us 128KB per request handler thread at the cost of this scary comment. */
 
-    TRACE("[%d] READ %p(%d) %u@%llu\n", handler->token,
-            h, h->fd, size, offset);
+    TRACE("[%d] READ %p(%d) %u@%"PRIu64"\n", handler->token,
+            h, h->fd, size, (uint64_t) offset);
     if (size > MAX_READ) {
         return -EINVAL;
     }
@@ -1253,7 +1261,7 @@
         buffer = (const __u8*) aligned_buffer;
     }
 
-    TRACE("[%d] WRITE %p(%d) %u@%llu\n", handler->token,
+    TRACE("[%d] WRITE %p(%d) %u@%"PRIu64"\n", handler->token,
             h, h->fd, req->size, req->offset);
     res = pwrite64(h->fd, buffer, req->size, req->offset);
     if (res < 0) {
@@ -1348,7 +1356,7 @@
 
     pthread_mutex_lock(&fuse->lock);
     node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
-    TRACE("[%d] OPENDIR @ %llx (%s)\n", handler->token,
+    TRACE("[%d] OPENDIR @ %"PRIx64" (%s)\n", handler->token,
             hdr->nodeid, node ? node->name : "?");
     pthread_mutex_unlock(&fuse->lock);
 
@@ -1549,7 +1557,7 @@
     }
 
     default: {
-        TRACE("[%d] NOTIMPL op=%d uniq=%llx nid=%llx\n",
+        TRACE("[%d] NOTIMPL op=%d uniq=%"PRIx64" nid=%"PRIx64"\n",
                 handler->token, hdr->opcode, hdr->unique, hdr->nodeid);
         return -ENOSYS;
     }
@@ -1652,7 +1660,7 @@
         }
     }
 
-    TRACE("read_package_list: found %d packages, %d with write_gid\n",
+    TRACE("read_package_list: found %zu packages, %zu with write_gid\n",
             hashmapSize(fuse->package_to_appid),
             hashmapSize(fuse->appid_with_rw));
     fclose(file);
@@ -1849,6 +1857,7 @@
     bool split_perms = false;
     int i;
     struct rlimit rlim;
+    int fs_version;
 
     int opt;
     while ((opt = getopt(argc, argv, "u:g:w:t:dls")) != -1) {
@@ -1923,6 +1932,11 @@
         ERROR("Error setting RLIMIT_NOFILE, errno = %d\n", errno);
     }
 
+    while ((fs_read_atomic_int("/data/.layout_version", &fs_version) == -1) || (fs_version < 3)) {
+        ERROR("installd fs upgrade not yet complete. Waiting...\n");
+        sleep(1);
+    }
+
     res = run(source_path, dest_path, uid, gid, write_gid, num_threads, derive, split_perms);
     return res < 0 ? 1 : 0;
 }
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index c53f17d..d8d397e 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -1,104 +1,221 @@
 LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
 
-TOOLS := \
-	cat \
-	chcon \
-	chmod \
-	chown \
-	clear \
-	cmp \
-	date \
-	dd \
-	df \
-	dmesg \
-	du \
-	getenforce \
-	getevent \
-	getprop \
-	getsebool \
-	hd \
-	id \
-	ifconfig \
-	iftop \
-	insmod \
-	ioctl \
-	ionice \
-	kill \
-	ln \
-	load_policy \
-	log \
-	ls \
-	lsmod \
-	lsof \
-	md5 \
-	mkdir \
-	mknod \
-	mkswap \
-	mount \
-	mv \
-	nandread \
-	netstat \
-	newfs_msdos \
-	nohup \
-	notify \
-	printenv \
-	ps \
-	readlink \
-	renice \
-	restorecon \
-	rm \
-	rmdir \
-	rmmod \
-	route \
-	runcon \
-	schedtop \
-	sendevent \
-	setenforce \
-	setprop \
-	setsebool \
-	sleep \
-	smd \
-	start \
-	stop \
-	swapoff \
-	swapon \
-	sync \
-	top \
-	touch \
-	umount \
-	uptime \
-	vmstat \
-	watchprops \
-	wipe \
 
-ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
-TOOLS += r
-endif
-
-ALL_TOOLS = $(TOOLS)
-ALL_TOOLS += \
-	cp \
-	grep
-
-LOCAL_SRC_FILES := \
-	cp/cp.c \
-	cp/utils.c \
-	dynarray.c \
-	grep/fastgrep.c \
-	grep/file.c \
-	grep/grep.c \
-	grep/queue.c \
-	grep/util.c \
-	$(patsubst %,%.c,$(TOOLS)) \
-	toolbox.c \
-	uid_from_user.c \
-
-LOCAL_CFLAGS += \
+common_cflags := \
     -std=gnu99 \
     -Werror -Wno-unused-parameter \
+    -I$(LOCAL_PATH)/upstream-netbsd/include/ \
     -include bsd-compatibility.h \
 
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := upstream-netbsd/bin/cat/cat.c
+LOCAL_CFLAGS += $(common_cflags) -Dmain=cat_main
+LOCAL_MODULE := libtoolbox_cat
+LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := upstream-netbsd/sbin/chown/chown.c
+LOCAL_CFLAGS += $(common_cflags) -Dmain=chown_main
+LOCAL_MODULE := libtoolbox_chown
+LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := \
+    upstream-netbsd/bin/cp/cp.c \
+    upstream-netbsd/bin/cp/utils.c
+LOCAL_CFLAGS += $(common_cflags) -Dmain=cp_main
+LOCAL_MODULE := libtoolbox_cp
+LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := \
+    upstream-netbsd/bin/dd/args.c \
+    upstream-netbsd/bin/dd/conv.c \
+    upstream-netbsd/bin/dd/dd.c \
+    upstream-netbsd/bin/dd/dd_hostops.c \
+    upstream-netbsd/bin/dd/misc.c \
+    upstream-netbsd/bin/dd/position.c
+LOCAL_CFLAGS += $(common_cflags) -Dmain=dd_main -DNO_CONV
+LOCAL_MODULE := libtoolbox_dd
+LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := upstream-netbsd/usr.bin/du/du.c
+LOCAL_CFLAGS += $(common_cflags) -Dmain=du_main
+LOCAL_MODULE := libtoolbox_du
+LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := \
+    upstream-netbsd/usr.bin/grep/fastgrep.c \
+    upstream-netbsd/usr.bin/grep/file.c \
+    upstream-netbsd/usr.bin/grep/grep.c \
+    upstream-netbsd/usr.bin/grep/queue.c \
+    upstream-netbsd/usr.bin/grep/util.c
+LOCAL_CFLAGS += $(common_cflags) -Dmain=grep_main
+LOCAL_MODULE := libtoolbox_grep
+LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := upstream-netbsd/bin/kill/kill.c
+LOCAL_CFLAGS += $(common_cflags) -Dmain=kill_main
+LOCAL_MODULE := libtoolbox_kill
+LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := upstream-netbsd/bin/ln/ln.c
+LOCAL_CFLAGS += $(common_cflags) -Dmain=ln_main
+LOCAL_MODULE := libtoolbox_ln
+LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := upstream-netbsd/bin/mv/mv.c
+LOCAL_CFLAGS += $(common_cflags) -Dmain=mv_main -D__SVR4
+LOCAL_MODULE := libtoolbox_mv
+LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := upstream-netbsd/usr.bin/printenv/printenv.c
+LOCAL_CFLAGS += $(common_cflags) -Dmain=printenv_main
+LOCAL_MODULE := libtoolbox_printenv
+LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := upstream-netbsd/bin/rm/rm.c
+LOCAL_CFLAGS += $(common_cflags) -Dmain=rm_main
+LOCAL_MODULE := libtoolbox_rm
+LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := upstream-netbsd/bin/rmdir/rmdir.c
+LOCAL_CFLAGS += $(common_cflags) -Dmain=rmdir_main
+LOCAL_MODULE := libtoolbox_rmdir
+LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := upstream-netbsd/bin/sleep/sleep.c
+LOCAL_CFLAGS += $(common_cflags) -Dmain=sleep_main
+LOCAL_MODULE := libtoolbox_sleep
+LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := upstream-netbsd/bin/sync/sync.c
+LOCAL_CFLAGS += $(common_cflags) -Dmain=sync_main
+LOCAL_MODULE := libtoolbox_sync
+LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
+include $(BUILD_STATIC_LIBRARY)
+
+
+include $(CLEAR_VARS)
+
+BSD_TOOLS := \
+    cat \
+    chown \
+    cp \
+    dd \
+    du \
+    grep \
+    kill \
+    ln \
+    mv \
+    printenv \
+    rm \
+    rmdir \
+    sleep \
+    sync \
+
+OUR_TOOLS := \
+    chcon \
+    chmod \
+    clear \
+    cmp \
+    date \
+    df \
+    dmesg \
+    getenforce \
+    getevent \
+    getprop \
+    getsebool \
+    hd \
+    id \
+    ifconfig \
+    iftop \
+    insmod \
+    ioctl \
+    ionice \
+    load_policy \
+    log \
+    ls \
+    lsmod \
+    lsof \
+    md5 \
+    mkdir \
+    mknod \
+    mkswap \
+    mount \
+    nandread \
+    netstat \
+    newfs_msdos \
+    nohup \
+    notify \
+    ps \
+    readlink \
+    renice \
+    restorecon \
+    rmmod \
+    route \
+    runcon \
+    schedtop \
+    sendevent \
+    setenforce \
+    setprop \
+    setsebool \
+    smd \
+    start \
+    stop \
+    swapoff \
+    swapon \
+    top \
+    touch \
+    umount \
+    uptime \
+    vmstat \
+    watchprops \
+    wipe \
+
+ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
+OUR_TOOLS += r
+endif
+
+ALL_TOOLS = $(BSD_TOOLS) $(OUR_TOOLS)
+
+LOCAL_SRC_FILES := \
+    upstream-netbsd/lib/libc/gen/getbsize.c \
+    upstream-netbsd/lib/libc/gen/humanize_number.c \
+    upstream-netbsd/lib/libc/stdlib/strsuftoll.c \
+    upstream-netbsd/lib/libc/string/swab.c \
+    upstream-netbsd/lib/libutil/raise_default_signal.c \
+    dynarray.c \
+    pwcache.c \
+    $(patsubst %,%.c,$(OUR_TOOLS)) \
+    toolbox.c \
+
+LOCAL_CFLAGS += $(common_cflags)
+
 LOCAL_C_INCLUDES += external/openssl/include
 
 LOCAL_SHARED_LIBRARIES := \
@@ -111,6 +228,8 @@
 LOCAL_STATIC_LIBRARIES := \
     libusbhost \
 
+LOCAL_WHOLE_STATIC_LIBRARIES := $(patsubst %,libtoolbox_%,$(BSD_TOOLS))
+
 LOCAL_MODULE := toolbox
 LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
 
diff --git a/toolbox/NOTICE b/toolbox/NOTICE
index 895b49a..e9ab58d 100644
--- a/toolbox/NOTICE
+++ b/toolbox/NOTICE
@@ -1,5 +1,20 @@
+Copyright (C) 2010 The Android Open Source Project
 
-Copyright (c) 2010, 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.
+
+-------------------------------------------------------------------
+
+Copyright (C) 2014, The Android Open Source Project
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -9,12 +24,8 @@
    notice, this list of conditions and the following disclaimer.
  * Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in
-   the documentation and/or other materials provided with the 
+   the documentation and/or other materials provided with the
    distribution.
- * Neither the name of The Android Open Source Project nor the names
-   of its contributors may be used to endorse or promote products
-   derived from this software without specific prior written
-   permission.
 
 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
@@ -23,86 +34,16 @@
 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
-OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 SUCH DAMAGE.
 
+-------------------------------------------------------------------
 
-Copyright (c) 2009, The Android Open Source Project.
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
- * Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in
-   the documentation and/or other materials provided with the 
-   distribution.
- * Neither the name of The Android Open Source Project nor the names
-   of its contributors may be used to endorse or promote products
-   derived from this software without specific prior written
-   permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
-FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
-COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
-INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
-BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
-OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
-AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
-OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGE.
-
-
-Copyright (c) 2008, The Android Open Source Project.
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
- * Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in
-   the documentation and/or other materials provided with the 
-   distribution.
- * Neither the name of The Android Open Source Project nor the names
-   of its contributors may be used to endorse or promote products
-   derived from this software without specific prior written
-   permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
-FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
-COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
-INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
-BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
-OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
-AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
-OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGE.
-
-
-Copyright (c) 1998 Robert Nordier
-Copyright (c) 1989, 1993
-     The Regents of the University of California.  All rights reserved.
-
-This code is derived from software contributed to Berkeley by
-Kevin Fall.
-This code is derived from software contributed to Berkeley by
-Keith Muller of the University of California, San Diego and Lance
-Visser of Convex Computer Corporation.
-This code is derived from software contributed to Berkeley by
-Mike Muuss.
+Copyright (c) 1987, 1993
+   The Regents of the University of California.  All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions
@@ -128,66 +69,919 @@
 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 SUCH DAMAGE.
 
+-------------------------------------------------------------------
 
- Copyright (c) 1989, 1993
-	The Regents of the University of California.  All rights reserved.
+Copyright (c) 1987, 1993, 1994
+   The Regents of the University of California.  All rights reserved.
 
- This code is derived from software contributed to Berkeley by
- Kevin Fall.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name of the University nor the names of its contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
 
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
- 1. Redistributions of source code must retain the above copyright
-    notice, this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright
-    notice, this list of conditions and the following disclaimer in the
-    documentation and/or other materials provided with the distribution.
- 3. Neither the name of the University nor the names of its contributors
-    may be used to endorse or promote products derived from this software
-    without specific prior written permission.
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
 
- THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- SUCH DAMAGE.
+-------------------------------------------------------------------
 
+Copyright (c) 1988, 1993
+   The Regents of the University of California.  All rights reserved.
 
- Copyright (c) 1991, 1993, 1994
-	The Regents of the University of California.  All rights reserved.
+This code is derived from software contributed to Berkeley by
+Jeffrey Mogul.
 
- This code is derived from software contributed to Berkeley by
- Keith Muller of the University of California, San Diego and Lance
- Visser of Convex Computer Corporation.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name of the University nor the names of its contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
 
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
- 1. Redistributions of source code must retain the above copyright
-    notice, this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright
-    notice, this list of conditions and the following disclaimer in the
-    documentation and/or other materials provided with the distribution.
- 3. Neither the name of the University nor the names of its contributors
-    may be used to endorse or promote products derived from this software
-    without specific prior written permission.
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
 
- THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- SUCH DAMAGE.
+-------------------------------------------------------------------
+
+Copyright (c) 1988, 1993, 1994
+   The Regents of the University of California.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name of the University nor the names of its contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1988, 1993, 1994
+   The Regents of the University of California.  All rights reserved.
+
+This code is derived from software contributed to Berkeley by
+David Hitz of Auspex Systems Inc.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name of the University nor the names of its contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1988, 1993, 1994, 2003
+   The Regents of the University of California.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name of the University nor the names of its contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1989, 1993
+   The Regents of the University of California.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name of the University nor the names of its contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1989, 1993
+   The Regents of the University of California.  All rights reserved.
+
+This code is derived from software contributed to Berkeley by
+Kevin Fall.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name of the University nor the names of its contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1989, 1993, 1994
+   The Regents of the University of California.  All rights reserved.
+
+This code is derived from software contributed to Berkeley by
+Chris Newcomb.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name of the University nor the names of its contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1989, 1993, 1994
+   The Regents of the University of California.  All rights reserved.
+
+This code is derived from software contributed to Berkeley by
+Ken Smith of The State University of New York at Buffalo.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name of the University nor the names of its contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1990, 1993, 1994, 2003
+   The Regents of the University of California.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name of the University nor the names of its contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1991, 1993
+   The Regents of the University of California.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name of the University nor the names of its contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1991, 1993, 1994
+   The Regents of the University of California.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name of the University nor the names of its contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1991, 1993, 1994
+   The Regents of the University of California.  All rights reserved.
+
+This code is derived from software contributed to Berkeley by
+Keith Muller of the University of California, San Diego and Lance
+Visser of Convex Computer Corporation.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name of the University nor the names of its contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1992, 1993, 1994
+   The Regents of the University of California.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name of the University nor the names of its contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1997, 1998, 1999, 2002 The NetBSD Foundation, Inc.
+All rights reserved.
+
+This code is derived from software contributed to The NetBSD Foundation
+by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+NASA Ames Research Center, by Luke Mewburn and by Tomas Svensson.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1998 Robert Nordier
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in
+   the documentation and/or other materials provided with the
+   distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
+OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
+Copyright (C) 2008 Gabor Kovesdan <gabor@FreeBSD.org>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
+Copyright (C) 2008-2009 Gabor Kovesdan <gabor@FreeBSD.org>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
+Copyright (C) 2008-2010 Gabor Kovesdan <gabor@FreeBSD.org>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
+Copyright (C) 2008-2010 Gabor Kovesdan <gabor@FreeBSD.org>
+Copyright (C) 2010 Dimitry Andric <dimitry@andric.com>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
+Copyright (c) 2008-2009 Gabor Kovesdan <gabor@FreeBSD.org>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2001-2002,2004 The NetBSD Foundation, Inc.
+All rights reserved.
+
+This code is derived from software contributed to The NetBSD Foundation
+by Luke Mewburn.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2007 The NetBSD Foundation, Inc.
+All rights reserved.
+
+This code is derived from software contributed to The NetBSD Foundation
+by Luke Mewburn.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2008, The Android Open Source Project
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+ * Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in
+   the documentation and/or other materials provided with the
+   distribution.
+ * Neither the name of Google, Inc. nor the names of its contributors
+   may be used to endorse or promote products derived from this
+   software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2009, The Android Open Source Project
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+ * Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in
+   the documentation and/or other materials provided with the
+   distribution.
+ * Neither the name of Google, Inc. nor the names of its contributors
+   may be used to endorse or promote products derived from this
+   software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2010 The NetBSD Foundation, Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2010, The Android Open Source Project
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+ * Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in
+   the documentation and/or other materials provided with the
+   distribution.
+ * Neither the name of Google, Inc. nor the names of its contributors
+   may be used to endorse or promote products derived from this
+   software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2012, The Android Open Source Project
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+ * Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in
+   the documentation and/or other materials provided with the
+   distribution.
+ * Neither the name of Google, Inc. nor the names of its contributors
+   may be used to endorse or promote products derived from this
+   software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2013, The Android Open Source Project
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+ * Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in
+   the documentation and/or other materials provided with the
+   distribution.
+ * Neither the name of Google, Inc. nor the names of its contributors
+   may be used to endorse or promote products derived from this
+   software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+-------------------------------------------------------------------
+
+Copyright (c) 2014, The Android Open Source Project
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+ * Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in
+   the documentation and/or other materials provided with the
+   distribution.
+ * Neither the name of Google, Inc. nor the names of its contributors
+   may be used to endorse or promote products derived from this
+   software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
+-------------------------------------------------------------------
 
diff --git a/toolbox/bsd-compatibility.h b/toolbox/bsd-compatibility.h
index a304631..9c6c34a 100644
--- a/toolbox/bsd-compatibility.h
+++ b/toolbox/bsd-compatibility.h
@@ -26,13 +26,67 @@
  * SUCH DAMAGE.
  */
 
+#include <stdbool.h>
 #include <sys/types.h>
 
 /* We want chown to support user.group as well as user:group. */
 #define SUPPORT_DOT
 
+/* We don't localize /system/bin! */
+#define WITHOUT_NLS
+
+// NetBSD uses _DIAGASSERT to null-check arguments and the like.
+#include <assert.h>
+#define _DIAGASSERT(e) ((e) ? (void) 0 : __assert2(__FILE__, __LINE__, __func__, #e))
+
+// TODO: update our <sys/cdefs.h> to support this properly.
+#define __type_fit(t, a) (0 == 0)
+
+// TODO: should this be in our <sys/cdefs.h>?
+#define __arraycount(a) (sizeof(a) / sizeof(a[0]))
+
+// This at least matches GNU dd(1) behavior.
+#define SIGINFO SIGUSR1
+
+#define S_ISWHT(x) false
+
+// TODO: should this be in bionic? (glibc does this, even though it's not quite right.)
+#define O_RSYNC O_SYNC
+
 __BEGIN_DECLS
 
-extern int uid_from_user(const char* name, uid_t* uid);
+/* From NetBSD <grp.h> and <pwd.h>. */
+char* group_from_gid(gid_t gid, int noname);
+int uid_from_user(const char* name, uid_t* uid);
+char* user_from_uid(uid_t uid, int noname);
+
+/* From NetBSD <stdlib.h>. */
+#define HN_DECIMAL              0x01
+#define HN_NOSPACE              0x02
+#define HN_B                    0x04
+#define HN_DIVISOR_1000         0x08
+#define HN_GETSCALE             0x10
+#define HN_AUTOSCALE            0x20
+int	humanize_number(char *, size_t, int64_t, const char *, int, int);
+int	dehumanize_number(const char *, int64_t *);
+char	*getbsize(int *, long *);
+long long strsuftoll(const char *, const char *, long long, long long);
+long long strsuftollx(const char *, const char *, long long, long long,
+			char *, size_t);
+
+/* From NetBSD <string.h>. */
+void strmode(mode_t, char*);
+
+/* From NetBSD <sys/param.h>. */
+#define MAXBSIZE 65536
+
+/* From NetBSD <sys/stat.h>. */
+#define DEFFILEMODE (S_IRUSR | S_IWUSR)
+
+/* From NetBSD <unistd.h>. */
+void	swab(const void * __restrict, void * __restrict, ssize_t);
+
+/* From NetBSD <util.h>. */
+int		raise_default_signal(int);
 
 __END_DECLS
diff --git a/toolbox/dd.c b/toolbox/dd.c
deleted file mode 100644
index 408a496..0000000
--- a/toolbox/dd.c
+++ /dev/null
@@ -1,1313 +0,0 @@
-/*	$NetBSD: dd.c,v 1.37 2004/01/17 21:00:16 dbj Exp $	*/
-
-/*-
- * Copyright (c) 1991, 1993, 1994
- *	The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Keith Muller of the University of California, San Diego and Lance
- * Visser of Convex Computer Corporation.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-#ifndef lint
-__COPYRIGHT("@(#) Copyright (c) 1991, 1993, 1994\n\
-	The Regents of the University of California.  All rights reserved.\n");
-#endif /* not lint */
-
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)dd.c	8.5 (Berkeley) 4/2/94";
-#else
-__RCSID("$NetBSD: dd.c,v 1.37 2004/01/17 21:00:16 dbj Exp $");
-#endif
-#endif /* not lint */
-
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <sys/time.h>
-
-#include <ctype.h>
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "dd.h"
-
-//#define NO_CONV
-
-//#include "extern.h"
-void block(void);
-void block_close(void);
-void dd_out(int);
-void def(void);
-void def_close(void);
-void jcl(char **);
-void pos_in(void);
-void pos_out(void);
-void summary(void);
-void summaryx(int);
-void terminate(int);
-void unblock(void);
-void unblock_close(void);
-ssize_t bwrite(int, const void *, size_t);
-
-extern IO		in, out;
-extern STAT		st;
-extern void		(*cfunc)(void);
-extern uint64_t		cpy_cnt;
-extern uint64_t		cbsz;
-extern u_int		ddflags;
-extern u_int		files_cnt;
-extern int		progress;
-extern const u_char	*ctab;
-
-#define DEFFILEMODE (S_IRUSR | S_IWUSR)
-
-static void dd_close(void);
-static void dd_in(void);
-static void getfdtype(IO *);
-static int redup_clean_fd(int);
-static void setup(void);
-
-
-IO		in, out;		/* input/output state */
-STAT		st;			/* statistics */
-void		(*cfunc)(void);		/* conversion function */
-uint64_t	cpy_cnt;		/* # of blocks to copy */
-static off_t	pending = 0;		/* pending seek if sparse */
-u_int		ddflags;		/* conversion options */
-uint64_t	cbsz;			/* conversion block size */
-u_int		files_cnt = 1;		/* # of files to copy */
-int		progress = 0;		/* display sign of life */
-const u_char	*ctab;			/* conversion table */
-sigset_t	infoset;		/* a set blocking SIGINFO */
-
-int
-dd_main(int argc, char *argv[])
-{
-	int ch;
-
-	while ((ch = getopt(argc, argv, "")) != -1) {
-		switch (ch) {
-		default:
-			fprintf(stderr, "usage: dd [operand ...]\n");
-			exit(1);
-			/* NOTREACHED */
-		}
-	}
-	argc -= (optind - 1);
-	argv += (optind - 1);
-
-	jcl(argv);
-	setup();
-
-//	(void)signal(SIGINFO, summaryx);
-	(void)signal(SIGINT, terminate);
-	(void)sigemptyset(&infoset);
-//	(void)sigaddset(&infoset, SIGINFO);
-
-	(void)atexit(summary);
-
-	while (files_cnt--)
-		dd_in();
-
-	dd_close();
-	exit(0);
-	/* NOTREACHED */
-}
-
-static void
-setup(void)
-{
-
-	if (in.name == NULL) {
-		in.name = "stdin";
-		in.fd = STDIN_FILENO;
-	} else {
-		in.fd = open(in.name, O_RDONLY, 0);
-		if (in.fd < 0) {
-			fprintf(stderr, "%s: cannot open for read: %s\n",
-				in.name, strerror(errno));
-			exit(1);
-			/* NOTREACHED */
-		}
-
-		/* Ensure in.fd is outside the stdio descriptor range */
-		in.fd = redup_clean_fd(in.fd);
-	}
-
-	getfdtype(&in);
-
-	if (files_cnt > 1 && !(in.flags & ISTAPE)) {
-		fprintf(stderr,
-			"files is not supported for non-tape devices\n");
-		exit(1);
-		/* NOTREACHED */
-	}
-
-	if (out.name == NULL) {
-		/* No way to check for read access here. */
-		out.fd = STDOUT_FILENO;
-		out.name = "stdout";
-	} else {
-#define	OFLAGS \
-    (O_CREAT | (ddflags & (C_SEEK | C_NOTRUNC) ? 0 : O_TRUNC))
-		out.fd = open(out.name, O_RDWR | OFLAGS, DEFFILEMODE);
-		/*
-		 * May not have read access, so try again with write only.
-		 * Without read we may have a problem if output also does
-		 * not support seeks.
-		 */
-		if (out.fd < 0) {
-			out.fd = open(out.name, O_WRONLY | OFLAGS, DEFFILEMODE);
-			out.flags |= NOREAD;
-		}
-		if (out.fd < 0) {
-			fprintf(stderr, "%s: cannot open for write: %s\n",
-				out.name, strerror(errno));
-			exit(1);
-			/* NOTREACHED */
-		}
-
-		/* Ensure out.fd is outside the stdio descriptor range */
-		out.fd = redup_clean_fd(out.fd);
-	}
-
-	getfdtype(&out);
-
-	/*
-	 * Allocate space for the input and output buffers.  If not doing
-	 * record oriented I/O, only need a single buffer.
-	 */
-	if (!(ddflags & (C_BLOCK|C_UNBLOCK))) {
-		if ((in.db = malloc(out.dbsz + in.dbsz - 1)) == NULL) {
-			exit(1);
-			/* NOTREACHED */
-		}
-		out.db = in.db;
-	} else if ((in.db =
-	    malloc((u_int)(MAX(in.dbsz, cbsz) + cbsz))) == NULL ||
-	    (out.db = malloc((u_int)(out.dbsz + cbsz))) == NULL) {
-		exit(1);
-		/* NOTREACHED */
-	}
-	in.dbp = in.db;
-	out.dbp = out.db;
-
-	/* Position the input/output streams. */
-	if (in.offset)
-		pos_in();
-	if (out.offset)
-		pos_out();
-
-	/*
-	 * Truncate the output file; ignore errors because it fails on some
-	 * kinds of output files, tapes, for example.
-	 */
-	if ((ddflags & (C_OF | C_SEEK | C_NOTRUNC)) == (C_OF | C_SEEK))
-		(void)ftruncate(out.fd, (off_t)out.offset * out.dbsz);
-
-	(void)gettimeofday(&st.start, NULL);	/* Statistics timestamp. */
-}
-
-static void
-getfdtype(IO *io)
-{
-//	struct mtget mt;
-	struct stat sb;
-
-	if (fstat(io->fd, &sb)) {
-		fprintf(stderr, "%s: cannot fstat: %s\n",
-			io->name, strerror(errno));
-		exit(1);
-		/* NOTREACHED */
-	}
-	if (S_ISCHR(sb.st_mode))
-		io->flags |= /*ioctl(io->fd, MTIOCGET, &mt) ? ISCHR : ISTAPE; */ ISCHR;
-	else if (lseek(io->fd, (off_t)0, SEEK_CUR) == -1 && errno == ESPIPE)
-		io->flags |= ISPIPE;		/* XXX fixed in 4.4BSD */
-}
-
-/*
- * Move the parameter file descriptor to a descriptor that is outside the
- * stdio descriptor range, if necessary.  This is required to avoid
- * accidentally outputting completion or error messages into the
- * output file that were intended for the tty.
- */
-static int
-redup_clean_fd(int fd)
-{
-	int newfd;
-
-	if (fd != STDIN_FILENO && fd != STDOUT_FILENO &&
-	    fd != STDERR_FILENO)
-		/* File descriptor is ok, return immediately. */
-		return fd;
-
-	/*
-	 * 3 is the first descriptor greater than STD*_FILENO.  Any
-	 * free descriptor valued 3 or above is acceptable...
-	 */
-	newfd = fcntl(fd, F_DUPFD, 3);
-	if (newfd < 0) {
-		fprintf(stderr, "dupfd IO: %s\n", strerror(errno));
-		exit(1);
-		/* NOTREACHED */
-	}
-
-	close(fd);
-
-	return newfd;
-}
-
-static void
-dd_in(void)
-{
-	int flags;
-	int64_t n;
-
-	for (flags = ddflags;;) {
-		if (cpy_cnt && (st.in_full + st.in_part) >= cpy_cnt)
-			return;
-
-		/*
-		 * Clear the buffer first if doing "sync" on input.
-		 * If doing block operations use spaces.  This will
-		 * affect not only the C_NOERROR case, but also the
-		 * last partial input block which should be padded
-		 * with zero and not garbage.
-		 */
-		if (flags & C_SYNC) {
-			if (flags & (C_BLOCK|C_UNBLOCK))
-				(void)memset(in.dbp, ' ', in.dbsz);
-			else
-				(void)memset(in.dbp, 0, in.dbsz);
-		}
-
-		n = read(in.fd, in.dbp, in.dbsz);
-		if (n == 0) {
-			in.dbrcnt = 0;
-			return;
-		}
-
-		/* Read error. */
-		if (n < 0) {
-
-			/*
-			 * If noerror not specified, die.  POSIX requires that
-			 * the warning message be followed by an I/O display.
-			 */
-			fprintf(stderr, "%s: read error: %s\n",
-				in.name, strerror(errno));
-			if (!(flags & C_NOERROR)) {
-				exit(1);
-				/* NOTREACHED */
-			}
-			summary();
-
-			/*
-			 * If it's not a tape drive or a pipe, seek past the
-			 * error.  If your OS doesn't do the right thing for
-			 * raw disks this section should be modified to re-read
-			 * in sector size chunks.
-			 */
-			if (!(in.flags & (ISPIPE|ISTAPE)) &&
-			    lseek(in.fd, (off_t)in.dbsz, SEEK_CUR))
-				fprintf(stderr, "%s: seek error: %s\n",
-					in.name, strerror(errno));
-
-			/* If sync not specified, omit block and continue. */
-			if (!(ddflags & C_SYNC))
-				continue;
-
-			/* Read errors count as full blocks. */
-			in.dbcnt += in.dbrcnt = in.dbsz;
-			++st.in_full;
-
-		/* Handle full input blocks. */
-		} else if (n == (int64_t)in.dbsz) {
-			in.dbcnt += in.dbrcnt = n;
-			++st.in_full;
-
-		/* Handle partial input blocks. */
-		} else {
-			/* If sync, use the entire block. */
-			if (ddflags & C_SYNC)
-				in.dbcnt += in.dbrcnt = in.dbsz;
-			else
-				in.dbcnt += in.dbrcnt = n;
-			++st.in_part;
-		}
-
-		/*
-		 * POSIX states that if bs is set and no other conversions
-		 * than noerror, notrunc or sync are specified, the block
-		 * is output without buffering as it is read.
-		 */
-		if (ddflags & C_BS) {
-			out.dbcnt = in.dbcnt;
-			dd_out(1);
-			in.dbcnt = 0;
-			continue;
-		}
-
-/*		if (ddflags & C_SWAB) {
-			if ((n = in.dbrcnt) & 1) {
-				++st.swab;
-				--n;
-			}
-			swab(in.dbp, in.dbp, n);
-		}
-*/
-		in.dbp += in.dbrcnt;
-		(*cfunc)();
-	}
-}
-
-/*
- * Cleanup any remaining I/O and flush output.  If necesssary, output file
- * is truncated.
- */
-static void
-dd_close(void)
-{
-
-	if (cfunc == def)
-		def_close();
-	else if (cfunc == block)
-		block_close();
-	else if (cfunc == unblock)
-		unblock_close();
-	if (ddflags & C_OSYNC && out.dbcnt < out.dbsz) {
-		(void)memset(out.dbp, 0, out.dbsz - out.dbcnt);
-		out.dbcnt = out.dbsz;
-	}
-	/* If there are pending sparse blocks, make sure
-	 * to write out the final block un-sparse
-	 */
-	if ((out.dbcnt == 0) && pending) {
-		memset(out.db, 0, out.dbsz);
-		out.dbcnt = out.dbsz;
-		out.dbp = out.db + out.dbcnt;
-		pending -= out.dbsz;
-	}
-	if (out.dbcnt)
-		dd_out(1);
-
-	/*
-	 * Reporting nfs write error may be defered until next
-	 * write(2) or close(2) system call.  So, we need to do an
-	 * extra check.  If an output is stdout, the file structure
-	 * may be shared among with other processes and close(2) just
-	 * decreases the reference count.
-	 */
-	if (out.fd == STDOUT_FILENO && fsync(out.fd) == -1 && errno != EINVAL) {
-		fprintf(stderr, "fsync stdout: %s\n", strerror(errno));
-		exit(1);
-		/* NOTREACHED */
-	}
-	if (close(out.fd) == -1) {
-		fprintf(stderr, "close: %s\n", strerror(errno));
-		exit(1);
-		/* NOTREACHED */
-	}
-}
-
-void
-dd_out(int force)
-{
-	static int warned;
-	int64_t cnt, n, nw;
-	u_char *outp;
-
-	/*
-	 * Write one or more blocks out.  The common case is writing a full
-	 * output block in a single write; increment the full block stats.
-	 * Otherwise, we're into partial block writes.  If a partial write,
-	 * and it's a character device, just warn.  If a tape device, quit.
-	 *
-	 * The partial writes represent two cases.  1: Where the input block
-	 * was less than expected so the output block was less than expected.
-	 * 2: Where the input block was the right size but we were forced to
-	 * write the block in multiple chunks.  The original versions of dd(1)
-	 * never wrote a block in more than a single write, so the latter case
-	 * never happened.
-	 *
-	 * One special case is if we're forced to do the write -- in that case
-	 * we play games with the buffer size, and it's usually a partial write.
-	 */
-	outp = out.db;
-	for (n = force ? out.dbcnt : out.dbsz;; n = out.dbsz) {
-		for (cnt = n;; cnt -= nw) {
-
-			if (!force && ddflags & C_SPARSE) {
-				int sparse, i;
-				sparse = 1;	/* Is buffer sparse? */
-				for (i = 0; i < cnt; i++)
-					if (outp[i] != 0) {
-						sparse = 0;
-						break;
-					}
-				if (sparse) {
-					pending += cnt;
-					outp += cnt;
-					nw = 0;
-					break;
-				}
-			}
-			if (pending != 0) {
-				if (lseek(out.fd, pending, SEEK_CUR) ==
-				    -1) {
-					fprintf(stderr,
-						"%s: seek error creating "
-						"sparse file: %s\n",
-						out.name, strerror(errno));
-					exit(1);
-				}
-			}
-			nw = bwrite(out.fd, outp, cnt);
-			if (nw <= 0) {
-				if (nw == 0) {
-					fprintf(stderr, "%s: end of device\n",
-						out.name);
-					exit(1);
-					/* NOTREACHED */
-				}
-				if (errno != EINTR) {
-					fprintf(stderr, "%s: write error: %s\n",
-						out.name, strerror(errno));
-					/* NOTREACHED */
-					exit(1);
-				}
-				nw = 0;
-			}
-			if (pending) {
-				st.bytes += pending;
-				st.sparse += pending/out.dbsz;
-				st.out_full += pending/out.dbsz;
-				pending = 0;
-			}
-			outp += nw;
-			st.bytes += nw;
-			if (nw == n) {
-				if (n != (int64_t)out.dbsz)
-					++st.out_part;
-				else
-					++st.out_full;
-				break;
-			}
-			++st.out_part;
-			if (nw == cnt)
-				break;
-			if (out.flags & ISCHR && !warned) {
-				warned = 1;
-				fprintf(stderr, "%s: short write on character "
-					"device\n", out.name);
-			}
-			if (out.flags & ISTAPE) {
-				fprintf(stderr,
-					"%s: short write on tape device",
-					out.name);
-				exit(1);
-				/* NOTREACHED */
-			}
-		}
-		if ((out.dbcnt -= n) < out.dbsz)
-			break;
-	}
-
-	/* Reassemble the output block. */
-	if (out.dbcnt)
-		(void)memmove(out.db, out.dbp - out.dbcnt, out.dbcnt);
-	out.dbp = out.db + out.dbcnt;
-
-	if (progress)
-		(void)write(STDERR_FILENO, ".", 1);
-}
-
-/*
- * A protected against SIGINFO write
- */
-ssize_t
-bwrite(int fd, const void *buf, size_t len)
-{
-	sigset_t oset;
-	ssize_t rv;
-	int oerrno;
-
-	(void)sigprocmask(SIG_BLOCK, &infoset, &oset);
-	rv = write(fd, buf, len);
-	oerrno = errno;
-	(void)sigprocmask(SIG_SETMASK, &oset, NULL);
-	errno = oerrno;
-	return (rv);
-}
-
-/*
- * Position input/output data streams before starting the copy.  Device type
- * dependent.  Seekable devices use lseek, and the rest position by reading.
- * Seeking past the end of file can cause null blocks to be written to the
- * output.
- */
-void
-pos_in(void)
-{
-	int bcnt, cnt, nr, warned;
-
-	/* If not a pipe or tape device, try to seek on it. */
-	if (!(in.flags & (ISPIPE|ISTAPE))) {
-		if (lseek64(in.fd,
-		    (off64_t)in.offset * (off64_t)in.dbsz, SEEK_CUR) == -1) {
-			fprintf(stderr, "%s: seek error: %s",
-				in.name, strerror(errno));
-			exit(1);
-			/* NOTREACHED */
-		}
-		return;
-		/* NOTREACHED */
-	}
-
-	/*
-	 * Read the data.  If a pipe, read until satisfy the number of bytes
-	 * being skipped.  No differentiation for reading complete and partial
-	 * blocks for other devices.
-	 */
-	for (bcnt = in.dbsz, cnt = in.offset, warned = 0; cnt;) {
-		if ((nr = read(in.fd, in.db, bcnt)) > 0) {
-			if (in.flags & ISPIPE) {
-				if (!(bcnt -= nr)) {
-					bcnt = in.dbsz;
-					--cnt;
-				}
-			} else
-				--cnt;
-			continue;
-		}
-
-		if (nr == 0) {
-			if (files_cnt > 1) {
-				--files_cnt;
-				continue;
-			}
-			fprintf(stderr, "skip reached end of input\n");
-			exit(1);
-			/* NOTREACHED */
-		}
-
-		/*
-		 * Input error -- either EOF with no more files, or I/O error.
-		 * If noerror not set die.  POSIX requires that the warning
-		 * message be followed by an I/O display.
-		 */
-		if (ddflags & C_NOERROR) {
-			if (!warned) {
-
-				fprintf(stderr, "%s: error occurred\n",
-					in.name);
-				warned = 1;
-				summary();
-			}
-			continue;
-		}
-		fprintf(stderr, "%s: read error: %s", in.name, strerror(errno));
-		exit(1);
-		/* NOTREACHED */
-	}
-}
-
-void
-pos_out(void)
-{
-/*	struct mtop t_op;        */
-	int64_t cnt, n;
-
-	/*
-	 * If not a tape, try seeking on the file.  Seeking on a pipe is
-	 * going to fail, but don't protect the user -- they shouldn't
-	 * have specified the seek operand.
-	 */
-	if (!(out.flags & ISTAPE)) {
-		if (lseek64(out.fd,
-		    (off64_t)out.offset * (off64_t)out.dbsz, SEEK_SET) == -1) {
-			fprintf(stderr, "%s: seek error: %s\n",
-				out.name, strerror(errno));
-			exit(1);
-			/* NOTREACHED */
-		}
-		return;
-	}
-
-	/* If no read access, try using mtio. */
-	if (out.flags & NOREAD) {
-/*		t_op.mt_op = MTFSR;
-		t_op.mt_count = out.offset;
-
-		if (ioctl(out.fd, MTIOCTOP, &t_op) < 0)*/
-			fprintf(stderr, "%s: cannot read", out.name);
-			exit(1);
-			/* NOTREACHED */
-		return;
-	}
-
-	/* Read it. */
-	for (cnt = 0; cnt < (int64_t)out.offset; ++cnt) {
-		if ((n = read(out.fd, out.db, out.dbsz)) > 0)
-			continue;
-
-		if (n < 0) {
-			fprintf(stderr, "%s: cannot position by reading: %s\n",
-				out.name, strerror(errno));
-			exit(1);
-			/* NOTREACHED */
-		}
-
-		/*
-		 * If reach EOF, fill with NUL characters; first, back up over
-		 * the EOF mark.  Note, cnt has not yet been incremented, so
-		 * the EOF read does not count as a seek'd block.
-		 */
-/*		t_op.mt_op = MTBSR;
-		t_op.mt_count = 1;
-		if (ioctl(out.fd, MTIOCTOP, &t_op) == -1) */ {
-			fprintf(stderr, "%s: cannot position\n", out.name);
-			exit(1);
-			/* NOTREACHED */
-		}
-
-		while (cnt++ < (int64_t)out.offset)
-			if ((n = bwrite(out.fd, out.db, out.dbsz)) != (int64_t)out.dbsz) {
-				fprintf(stderr, "%s: cannot position "
-					"by writing: %s\n",
-					out.name, strerror(errno));
-				exit(1);
-				/* NOTREACHED */
-			}
-		break;
-	}
-}
-
-/*
- * def --
- * Copy input to output.  Input is buffered until reaches obs, and then
- * output until less than obs remains.  Only a single buffer is used.
- * Worst case buffer calculation is (ibs + obs - 1).
- */
-void
-def(void)
-{
-	uint64_t cnt;
-	u_char *inp;
-	const u_char *t;
-
-	if ((t = ctab) != NULL)
-		for (inp = in.dbp - (cnt = in.dbrcnt); cnt--; ++inp)
-			*inp = t[*inp];
-
-	/* Make the output buffer look right. */
-	out.dbp = in.dbp;
-	out.dbcnt = in.dbcnt;
-
-	if (in.dbcnt >= out.dbsz) {
-		/* If the output buffer is full, write it. */
-		dd_out(0);
-
-		/*
-		 * Ddout copies the leftover output to the beginning of
-		 * the buffer and resets the output buffer.  Reset the
-		 * input buffer to match it.
-	 	 */
-		in.dbp = out.dbp;
-		in.dbcnt = out.dbcnt;
-	}
-}
-
-void
-def_close(void)
-{
-	if (ddflags & C_FDATASYNC) {
-		fdatasync(out.fd);
-	}
-
-	/* Just update the count, everything is already in the buffer. */
-	if (in.dbcnt)
-		out.dbcnt = in.dbcnt;
-}
-
-#ifdef	NO_CONV
-/* Build a smaller version (i.e. for a miniroot) */
-/* These can not be called, but just in case...  */
-static const char no_block[] = "unblock and -DNO_CONV?\n";
-void block(void)		{ fprintf(stderr, "%s", no_block + 2); exit(1); }
-void block_close(void)		{ fprintf(stderr, "%s", no_block + 2); exit(1); }
-void unblock(void)		{ fprintf(stderr, "%s", no_block); exit(1); }
-void unblock_close(void)	{ fprintf(stderr, "%s", no_block); exit(1); }
-#else	/* NO_CONV */
-
-/*
- * Copy variable length newline terminated records with a max size cbsz
- * bytes to output.  Records less than cbs are padded with spaces.
- *
- * max in buffer:  MAX(ibs, cbsz)
- * max out buffer: obs + cbsz
- */
-void
-block(void)
-{
-	static int intrunc;
-	int ch = 0;	/* pacify gcc */
-	uint64_t cnt, maxlen;
-	u_char *inp, *outp;
-	const u_char *t;
-
-	/*
-	 * Record truncation can cross block boundaries.  If currently in a
-	 * truncation state, keep tossing characters until reach a newline.
-	 * Start at the beginning of the buffer, as the input buffer is always
-	 * left empty.
-	 */
-	if (intrunc) {
-		for (inp = in.db, cnt = in.dbrcnt;
-		    cnt && *inp++ != '\n'; --cnt);
-		if (!cnt) {
-			in.dbcnt = 0;
-			in.dbp = in.db;
-			return;
-		}
-		intrunc = 0;
-		/* Adjust the input buffer numbers. */
-		in.dbcnt = cnt - 1;
-		in.dbp = inp + cnt - 1;
-	}
-
-	/*
-	 * Copy records (max cbsz size chunks) into the output buffer.  The
-	 * translation is done as we copy into the output buffer.
-	 */
-	for (inp = in.dbp - in.dbcnt, outp = out.dbp; in.dbcnt;) {
-		maxlen = MIN(cbsz, in.dbcnt);
-		if ((t = ctab) != NULL)
-			for (cnt = 0;
-			    cnt < maxlen && (ch = *inp++) != '\n'; ++cnt)
-				*outp++ = t[ch];
-		else
-			for (cnt = 0;
-			    cnt < maxlen && (ch = *inp++) != '\n'; ++cnt)
-				*outp++ = ch;
-		/*
-		 * Check for short record without a newline.  Reassemble the
-		 * input block.
-		 */
-		if (ch != '\n' && in.dbcnt < cbsz) {
-			(void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt);
-			break;
-		}
-
-		/* Adjust the input buffer numbers. */
-		in.dbcnt -= cnt;
-		if (ch == '\n')
-			--in.dbcnt;
-
-		/* Pad short records with spaces. */
-		if (cnt < cbsz)
-			(void)memset(outp, ctab ? ctab[' '] : ' ', cbsz - cnt);
-		else {
-			/*
-			 * If the next character wouldn't have ended the
-			 * block, it's a truncation.
-			 */
-			if (!in.dbcnt || *inp != '\n')
-				++st.trunc;
-
-			/* Toss characters to a newline. */
-			for (; in.dbcnt && *inp++ != '\n'; --in.dbcnt);
-			if (!in.dbcnt)
-				intrunc = 1;
-			else
-				--in.dbcnt;
-		}
-
-		/* Adjust output buffer numbers. */
-		out.dbp += cbsz;
-		if ((out.dbcnt += cbsz) >= out.dbsz)
-			dd_out(0);
-		outp = out.dbp;
-	}
-	in.dbp = in.db + in.dbcnt;
-}
-
-void
-block_close(void)
-{
-
-	/*
-	 * Copy any remaining data into the output buffer and pad to a record.
-	 * Don't worry about truncation or translation, the input buffer is
-	 * always empty when truncating, and no characters have been added for
-	 * translation.  The bottom line is that anything left in the input
-	 * buffer is a truncated record.  Anything left in the output buffer
-	 * just wasn't big enough.
-	 */
-	if (in.dbcnt) {
-		++st.trunc;
-		(void)memmove(out.dbp, in.dbp - in.dbcnt, in.dbcnt);
-		(void)memset(out.dbp + in.dbcnt,
-		    ctab ? ctab[' '] : ' ', cbsz - in.dbcnt);
-		out.dbcnt += cbsz;
-	}
-}
-
-/*
- * Convert fixed length (cbsz) records to variable length.  Deletes any
- * trailing blanks and appends a newline.
- *
- * max in buffer:  MAX(ibs, cbsz) + cbsz
- * max out buffer: obs + cbsz
- */
-void
-unblock(void)
-{
-	uint64_t cnt;
-	u_char *inp;
-	const u_char *t;
-
-	/* Translation and case conversion. */
-	if ((t = ctab) != NULL)
-		for (cnt = in.dbrcnt, inp = in.dbp - 1; cnt--; inp--)
-			*inp = t[*inp];
-	/*
-	 * Copy records (max cbsz size chunks) into the output buffer.  The
-	 * translation has to already be done or we might not recognize the
-	 * spaces.
-	 */
-	for (inp = in.db; in.dbcnt >= cbsz; inp += cbsz, in.dbcnt -= cbsz) {
-		for (t = inp + cbsz - 1; t >= inp && *t == ' '; --t);
-		if (t >= inp) {
-			cnt = t - inp + 1;
-			(void)memmove(out.dbp, inp, cnt);
-			out.dbp += cnt;
-			out.dbcnt += cnt;
-		}
-		++out.dbcnt;
-		*out.dbp++ = '\n';
-		if (out.dbcnt >= out.dbsz)
-			dd_out(0);
-	}
-	if (in.dbcnt)
-		(void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt);
-	in.dbp = in.db + in.dbcnt;
-}
-
-void
-unblock_close(void)
-{
-	uint64_t cnt;
-	u_char *t;
-
-	if (in.dbcnt) {
-		warnx("%s: short input record", in.name);
-		for (t = in.db + in.dbcnt - 1; t >= in.db && *t == ' '; --t);
-		if (t >= in.db) {
-			cnt = t - in.db + 1;
-			(void)memmove(out.dbp, in.db, cnt);
-			out.dbp += cnt;
-			out.dbcnt += cnt;
-		}
-		++out.dbcnt;
-		*out.dbp++ = '\n';
-	}
-}
-
-#endif	/* NO_CONV */
-
-#define	tv2mS(tv) ((tv).tv_sec * 1000LL + ((tv).tv_usec + 500) / 1000)
-
-void
-summary(void)
-{
-	char buf[100];
-	int64_t mS;
-	struct timeval tv;
-
-	if (progress)
-		(void)write(STDERR_FILENO, "\n", 1);
-
-	(void)gettimeofday(&tv, NULL);
-	mS = tv2mS(tv) - tv2mS(st.start);
-	if (mS == 0)
-		mS = 1;
-	/* Use snprintf(3) so that we don't reenter stdio(3). */
-	(void)snprintf(buf, sizeof(buf),
-	    "%llu+%llu records in\n%llu+%llu records out\n",
-	    (unsigned long long)st.in_full,  (unsigned long long)st.in_part,
-	    (unsigned long long)st.out_full, (unsigned long long)st.out_part);
-	(void)write(STDERR_FILENO, buf, strlen(buf));
-	if (st.swab) {
-		(void)snprintf(buf, sizeof(buf), "%llu odd length swab %s\n",
-		    (unsigned long long)st.swab,
-		    (st.swab == 1) ? "block" : "blocks");
-		(void)write(STDERR_FILENO, buf, strlen(buf));
-	}
-	if (st.trunc) {
-		(void)snprintf(buf, sizeof(buf), "%llu truncated %s\n",
-		    (unsigned long long)st.trunc,
-		    (st.trunc == 1) ? "block" : "blocks");
-		(void)write(STDERR_FILENO, buf, strlen(buf));
-	}
-	if (st.sparse) {
-		(void)snprintf(buf, sizeof(buf), "%llu sparse output %s\n",
-		    (unsigned long long)st.sparse,
-		    (st.sparse == 1) ? "block" : "blocks");
-		(void)write(STDERR_FILENO, buf, strlen(buf));
-	}
-	(void)snprintf(buf, sizeof(buf),
-	    "%llu bytes transferred in %lu.%03d secs (%llu bytes/sec)\n",
-	    (unsigned long long) st.bytes,
-	    (long) (mS / 1000),
-	    (int) (mS % 1000),
-	    (unsigned long long) (st.bytes * 1000LL / mS));
-	(void)write(STDERR_FILENO, buf, strlen(buf));
-}
-
-void
-terminate(int notused)
-{
-
-	exit(0);
-	/* NOTREACHED */
-}
-
-static int	c_arg(const void *, const void *);
-#ifndef	NO_CONV
-static int	c_conv(const void *, const void *);
-#endif
-static void	f_bs(char *);
-static void	f_cbs(char *);
-static void	f_conv(char *);
-static void	f_count(char *);
-static void	f_files(char *);
-static void	f_ibs(char *);
-static void	f_if(char *);
-static void	f_obs(char *);
-static void	f_of(char *);
-static void	f_seek(char *);
-static void	f_skip(char *);
-static void	f_progress(char *);
-
-static const struct arg {
-	const char *name;
-	void (*f)(char *);
-	u_int set, noset;
-} args[] = {
-     /* the array needs to be sorted by the first column so
-	bsearch() can be used to find commands quickly */
-	{ "bs",		f_bs,		C_BS,	 C_BS|C_IBS|C_OBS|C_OSYNC },
-	{ "cbs",	f_cbs,		C_CBS,	 C_CBS },
-	{ "conv",	f_conv,		0,	 0 },
-	{ "count",	f_count,	C_COUNT, C_COUNT },
-	{ "files",	f_files,	C_FILES, C_FILES },
-	{ "ibs",	f_ibs,		C_IBS,	 C_BS|C_IBS },
-	{ "if",		f_if,		C_IF,	 C_IF },
-	{ "obs",	f_obs,		C_OBS,	 C_BS|C_OBS },
-	{ "of",		f_of,		C_OF,	 C_OF },
-	{ "progress",	f_progress,	0,	 0 },
-	{ "seek",	f_seek,		C_SEEK,	 C_SEEK },
-	{ "skip",	f_skip,		C_SKIP,	 C_SKIP },
-};
-
-/*
- * args -- parse JCL syntax of dd.
- */
-void
-jcl(char **argv)
-{
-	struct arg *ap, tmp;
-	char *oper, *arg;
-
-	in.dbsz = out.dbsz = 512;
-
-	while ((oper = *++argv) != NULL) {
-		if ((arg = strchr(oper, '=')) == NULL) {
-			fprintf(stderr, "unknown operand %s\n", oper);
-			exit(1);
-			/* NOTREACHED */
-		}
-		*arg++ = '\0';
-		if (!*arg) {
-			fprintf(stderr, "no value specified for %s\n", oper);
-			exit(1);
-			/* NOTREACHED */
-		}
-		tmp.name = oper;
-		if (!(ap = (struct arg *)bsearch(&tmp, args,
-		    sizeof(args)/sizeof(struct arg), sizeof(struct arg),
-		    c_arg))) {
-			fprintf(stderr, "unknown operand %s\n", tmp.name);
-			exit(1);
-			/* NOTREACHED */
-		}
-		if (ddflags & ap->noset) {
-			fprintf(stderr,
-			    "%s: illegal argument combination or already set\n",
-			    tmp.name);
-			exit(1);
-			/* NOTREACHED */
-		}
-		ddflags |= ap->set;
-		ap->f(arg);
-	}
-
-	/* Final sanity checks. */
-
-	if (ddflags & C_BS) {
-		/*
-		 * Bs is turned off by any conversion -- we assume the user
-		 * just wanted to set both the input and output block sizes
-		 * and didn't want the bs semantics, so we don't warn.
-		 */
-		if (ddflags & (C_BLOCK | C_LCASE | C_SWAB | C_UCASE |
-		    C_UNBLOCK | C_OSYNC | C_ASCII | C_EBCDIC | C_SPARSE)) {
-			ddflags &= ~C_BS;
-			ddflags |= C_IBS|C_OBS;
-		}
-
-		/* Bs supersedes ibs and obs. */
-		if (ddflags & C_BS && ddflags & (C_IBS|C_OBS))
-			fprintf(stderr, "bs supersedes ibs and obs\n");
-	}
-
-	/*
-	 * Ascii/ebcdic and cbs implies block/unblock.
-	 * Block/unblock requires cbs and vice-versa.
-	 */
-	if (ddflags & (C_BLOCK|C_UNBLOCK)) {
-		if (!(ddflags & C_CBS)) {
-			fprintf(stderr, "record operations require cbs\n");
-			exit(1);
-			/* NOTREACHED */
-		}
-		cfunc = ddflags & C_BLOCK ? block : unblock;
-	} else if (ddflags & C_CBS) {
-		if (ddflags & (C_ASCII|C_EBCDIC)) {
-			if (ddflags & C_ASCII) {
-				ddflags |= C_UNBLOCK;
-				cfunc = unblock;
-			} else {
-				ddflags |= C_BLOCK;
-				cfunc = block;
-			}
-		} else {
-			fprintf(stderr,
-			    "cbs meaningless if not doing record operations\n");
-			exit(1);
-			/* NOTREACHED */
-		}
-	} else
-		cfunc = def;
-
-	/* Read, write and seek calls take off_t as arguments.
-	 *
-	 * The following check is not done because an off_t is a quad
-	 *  for current NetBSD implementations.
-	 *
-	 * if (in.offset > INT_MAX/in.dbsz || out.offset > INT_MAX/out.dbsz)
-	 *	errx(1, "seek offsets cannot be larger than %d", INT_MAX);
-	 */
-}
-
-static int
-c_arg(const void *a, const void *b)
-{
-
-	return (strcmp(((const struct arg *)a)->name,
-	    ((const struct arg *)b)->name));
-}
-
-static long long strsuftoll(const char* name, const char* arg, int def, unsigned long long max)
-{
-	long long result;
-	
-	if (sscanf(arg, "%lld", &result) == 0)
-		result = def;
-	return result;
-}
-
-static void
-f_bs(char *arg)
-{
-
-	in.dbsz = out.dbsz = strsuftoll("block size", arg, 1, UINT_MAX);
-}
-
-static void
-f_cbs(char *arg)
-{
-
-	cbsz = strsuftoll("conversion record size", arg, 1, UINT_MAX);
-}
-
-static void
-f_count(char *arg)
-{
-
-	cpy_cnt = (uint64_t)strsuftoll("block count", arg, 0, 0xFFFFFFFFFFFFFFFFULL);
-	if (!cpy_cnt)
-		terminate(0);
-}
-
-static void
-f_files(char *arg)
-{
-
-	files_cnt = (u_int)strsuftoll("file count", arg, 0, UINT_MAX);
-	if (!files_cnt)
-		terminate(0);
-}
-
-static void
-f_ibs(char *arg)
-{
-
-	if (!(ddflags & C_BS))
-		in.dbsz = strsuftoll("input block size", arg, 1, UINT_MAX);
-}
-
-static void
-f_if(char *arg)
-{
-
-	in.name = arg;
-}
-
-static void
-f_obs(char *arg)
-{
-
-	if (!(ddflags & C_BS))
-		out.dbsz = strsuftoll("output block size", arg, 1, UINT_MAX);
-}
-
-static void
-f_of(char *arg)
-{
-
-	out.name = arg;
-}
-
-static void
-f_seek(char *arg)
-{
-
-	out.offset = (uint64_t)strsuftoll("seek blocks", arg, 0, 0xFFFFFFFFFFFFFFFFULL);
-}
-
-static void
-f_skip(char *arg)
-{
-
-	in.offset = (uint64_t)strsuftoll("skip blocks", arg, 0, 0xFFFFFFFFFFFFFFFFULL);
-}
-
-static void
-f_progress(char *arg)
-{
-
-	if (*arg != '0')
-		progress = 1;
-}
-
-#ifdef	NO_CONV
-/* Build a small version (i.e. for a ramdisk root) */
-static void
-f_conv(char *arg)
-{
-
-	fprintf(stderr, "conv option disabled\n");
-	exit(1);
-	/* NOTREACHED */
-}
-#else	/* NO_CONV */
-
-static const struct conv {
-	const char *name;
-	u_int set, noset;
-	const u_char *ctab;
-} clist[] = {
-	{ "block",	C_BLOCK,	C_UNBLOCK,	NULL },
-	{ "fdatasync",	C_FDATASYNC,	0,		NULL },
-	{ "noerror",	C_NOERROR,	0,		NULL },
-	{ "notrunc",	C_NOTRUNC,	0,		NULL },
-	{ "osync",	C_OSYNC,	C_BS,		NULL },
-	{ "sparse",	C_SPARSE,	0,		NULL },
-	{ "swab",	C_SWAB,		0,		NULL },
-	{ "sync",	C_SYNC,		0,		NULL },
-	{ "unblock",	C_UNBLOCK,	C_BLOCK,	NULL },
-	/* If you add items to this table, be sure to add the
-	 * conversions to the C_BS check in the jcl routine above.
-	 */
-};
-
-static void
-f_conv(char *arg)
-{
-	struct conv *cp, tmp;
-
-	while (arg != NULL) {
-		tmp.name = strsep(&arg, ",");
-		if (!(cp = (struct conv *)bsearch(&tmp, clist,
-		    sizeof(clist)/sizeof(struct conv), sizeof(struct conv),
-		    c_conv))) {
-			errx(EXIT_FAILURE, "unknown conversion %s", tmp.name);
-			/* NOTREACHED */
-		}
-		if (ddflags & cp->noset) {
-			errx(EXIT_FAILURE, "%s: illegal conversion combination", tmp.name);
-			/* NOTREACHED */
-		}
-		ddflags |= cp->set;
-		if (cp->ctab)
-			ctab = cp->ctab;
-	}
-}
-
-static int
-c_conv(const void *a, const void *b)
-{
-
-	return (strcmp(((const struct conv *)a)->name,
-	    ((const struct conv *)b)->name));
-}
-
-#endif	/* NO_CONV */
-
-
diff --git a/toolbox/ioctl.c b/toolbox/ioctl.c
index 17fabff..fd90812 100644
--- a/toolbox/ioctl.c
+++ b/toolbox/ioctl.c
@@ -63,10 +63,14 @@
         exit(1);
     }
 
-    fd = open(argv[optind], O_RDWR | O_SYNC);
-    if (fd < 0) {
-        fprintf(stderr, "cannot open %s\n", argv[optind]);
-        return 1;
+    if (!strcmp(argv[optind], "-")) {
+        fd = STDIN_FILENO;
+    } else {
+        fd = open(argv[optind], read_only ? O_RDONLY : (O_RDWR | O_SYNC));
+        if (fd < 0) {
+            fprintf(stderr, "cannot open %s\n", argv[optind]);
+            return 1;
+        }
     }
     optind++;
     
diff --git a/toolbox/kill.c b/toolbox/kill.c
deleted file mode 100644
index fa2f649..0000000
--- a/toolbox/kill.c
+++ /dev/null
@@ -1,148 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-
-#include <sys/types.h>
-#include <signal.h>
-
-static struct {
-    unsigned int number;
-    char *name;
-} signals[] = {
-#define _SIG(name) {SIG##name, #name}
-    /* Single Unix Specification signals */
-    _SIG(ABRT),
-    _SIG(ALRM),
-    _SIG(FPE),
-    _SIG(HUP),
-    _SIG(ILL),
-    _SIG(INT),
-    _SIG(KILL),
-    _SIG(PIPE),
-    _SIG(QUIT),
-    _SIG(SEGV),
-    _SIG(TERM),
-    _SIG(USR1),
-    _SIG(USR2),
-    _SIG(CHLD),
-    _SIG(CONT),
-    _SIG(STOP),
-    _SIG(TSTP),
-    _SIG(TTIN),
-    _SIG(TTOU),
-    _SIG(BUS),
-    _SIG(POLL),
-    _SIG(PROF),
-    _SIG(SYS),
-    _SIG(TRAP),
-    _SIG(URG),
-    _SIG(VTALRM),
-    _SIG(XCPU),
-    _SIG(XFSZ),
-    /* non-SUS signals */
-    _SIG(IO),
-    _SIG(PWR),
-#ifdef SIGSTKFLT
-    _SIG(STKFLT),
-#endif
-    _SIG(WINCH),
-#undef _SIG
-};
-
-/* To indicate a matching signal was not found */
-static const unsigned int SENTINEL = (unsigned int) -1;
-
-void list_signals()
-{
-    unsigned int sorted_signals[_NSIG];
-    unsigned int i;
-    unsigned int num;
-
-    memset(sorted_signals, SENTINEL, sizeof(sorted_signals));
-
-    // Sort the signals
-    for (i = 0; i < sizeof(signals)/sizeof(signals[0]); i++) {
-        sorted_signals[signals[i].number] = i;
-    }
-
-    num = 0;
-    for (i = 1; i < _NSIG; i++) {
-        unsigned int index = sorted_signals[i];
-        if (index == SENTINEL) {
-            continue;
-        }
-
-        fprintf(stderr, "%2d) SIG%-9s ", i, signals[index].name);
-
-        if ((num++ % 4) == 3) {
-            fprintf(stderr, "\n");
-        }
-    }
-
-    if ((num % 4) == 3) {
-        fprintf(stderr, "\n");
-    }
-}
-
-unsigned int name_to_signal(const char* name)
-{
-    unsigned int i;
-
-    for (i = 1; i < sizeof(signals) / sizeof(signals[0]); i++) {
-        if (!strcasecmp(name, signals[i].name)) {
-            return signals[i].number;
-        }
-    }
-
-    return SENTINEL;
-}
-
-int kill_main(int argc, char **argv)
-{
-    unsigned int sig = SIGTERM;
-    int result = 0;
-
-    argc--;
-    argv++;
-
-    if (argc >= 1 && argv[0][0] == '-') {
-        char *endptr;
-        size_t arg_len = strlen(argv[0]);
-        if (arg_len < 2) {
-            fprintf(stderr, "invalid argument: -\n");
-            return -1;
-        }
-
-        char* arg = argv[0] + 1;
-        if (arg_len == 2 && *arg == 'l') {
-            list_signals();
-            return 0;
-        }
-
-        sig = strtol(arg, &endptr, 10);
-        if (*endptr != '\0') {
-            sig = name_to_signal(arg);
-            if (sig == SENTINEL) {
-                fprintf(stderr, "invalid signal name: %s\n", arg);
-                return -1;
-            }
-        }
-
-        argc--;
-        argv++;
-    }
-
-    while(argc > 0){
-        int pid = atoi(argv[0]);
-        int err = kill(pid, sig);
-        if (err < 0) {
-            result = err;
-            fprintf(stderr, "could not kill pid %d: %s\n", pid, strerror(errno));
-        }
-
-        argc--;
-        argv++;
-    }
-
-    return result;
-}
diff --git a/toolbox/ln.c b/toolbox/ln.c
deleted file mode 100644
index dcd5e3a..0000000
--- a/toolbox/ln.c
+++ /dev/null
@@ -1,34 +0,0 @@
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-
-static int usage()
-{
-    fprintf(stderr,"ln [-s] <target> <name>\n");
-    return -1;
-}
-
-int ln_main(int argc, char *argv[])
-{
-    int symbolic = 0;
-    int ret;
-    if(argc < 2) return usage();
-    
-    if(!strcmp(argv[1],"-s")) {
-        symbolic = 1;
-        argc--;
-        argv++;
-    }
-
-    if(argc < 3) return usage();
-
-    if(symbolic) {
-        ret = symlink(argv[1], argv[2]);
-    } else {
-        ret = link(argv[1], argv[2]);
-    }
-    if(ret < 0)
-        fprintf(stderr, "link failed %s\n", strerror(errno));
-    return ret;
-}
diff --git a/toolbox/ls.c b/toolbox/ls.c
index 011f7b5..963fcb5 100644
--- a/toolbox/ls.c
+++ b/toolbox/ls.c
@@ -33,7 +33,7 @@
 // fwd
 static int listpath(const char *name, int flags);
 
-static char mode2kind(unsigned mode)
+static char mode2kind(mode_t mode)
 {
     switch(mode & S_IFMT){
     case S_IFSOCK: return 's';
@@ -47,7 +47,7 @@
     }
 }
 
-static void mode2str(unsigned mode, char *out)
+void strmode(mode_t mode, char *out)
 {
     *out++ = mode2kind(mode);
 
@@ -180,7 +180,7 @@
         name++;
     }
 
-    mode2str(s->st_mode, mode);
+    strmode(s->st_mode, mode);
     if (flags & LIST_LONG_NUMERIC) {
         snprintf(user, sizeof(user), "%u", s->st_uid);
         snprintf(group, sizeof(group), "%u", s->st_gid);
@@ -260,7 +260,7 @@
         return -1;
     }
 
-    mode2str(s->st_mode, mode);
+    strmode(s->st_mode, mode);
     user2str(s->st_uid, user, sizeof(user));
     group2str(s->st_gid, group, sizeof(group));
 
diff --git a/toolbox/mv.c b/toolbox/mv.c
deleted file mode 100644
index a5bc225..0000000
--- a/toolbox/mv.c
+++ /dev/null
@@ -1,59 +0,0 @@
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <limits.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-
-int mv_main(int argc, char *argv[])
-{
-    const char* dest;
-    struct stat st;
-    int i;
-
-    if (argc < 3) {
-        fprintf(stderr,"USAGE: %s <source...> <destination>\n", argv[0]);
-        return -1;
-    }
-
-    /* check if destination exists */
-    dest = argv[argc - 1];
-    if (stat(dest, &st)) {
-        /* an error, unless the destination was missing */
-        if (errno != ENOENT) {
-            fprintf(stderr, "failed on %s - %s\n", dest, strerror(errno));
-            return -1;
-        }
-        st.st_mode = 0;
-    }
-
-    for (i = 1; i < argc - 1; i++) {
-        const char *source = argv[i];
-        char fullDest[PATH_MAX + 1 + PATH_MAX + 1];
-        /* assume we build "dest/source", and let rename() fail on pathsize */
-        if (strlen(dest) + 1 + strlen(source) + 1 > sizeof(fullDest)) {
-            fprintf(stderr, "path too long\n");
-            return -1;
-        }
-        strcpy(fullDest, dest);
-
-        /* if destination is a directory, concat the source file name */
-        if (S_ISDIR(st.st_mode)) {
-            const char *fileName = strrchr(source, '/');
-            if (fullDest[strlen(fullDest)-1] != '/') {
-                strcat(fullDest, "/");
-            }
-            strcat(fullDest, fileName ? fileName + 1 : source);
-        }
-
-        /* attempt to move it */
-        if (rename(source, fullDest)) {
-            fprintf(stderr, "failed on '%s' - %s\n", source, strerror(errno));
-            return -1;
-        }
-    }
-
-    return 0;
-}
-
diff --git a/toolbox/newfs_msdos.c b/toolbox/newfs_msdos.c
index 30b9f77..01517fd 100644
--- a/toolbox/newfs_msdos.c
+++ b/toolbox/newfs_msdos.c
@@ -27,20 +27,20 @@
 
 #ifndef lint
 static const char rcsid[] =
-  "$FreeBSD: src/sbin/newfs_msdos/newfs_msdos.c,v 1.33 2009/04/11 14:56:29 ed Exp $";
+        "$FreeBSD: src/sbin/newfs_msdos/newfs_msdos.c,v 1.33 2009/04/11 14:56:29 ed Exp $";
 #endif /* not lint */
 
 #include <sys/param.h>
 
 #ifndef ANDROID
-  #include <sys/fdcio.h>
-  #include <sys/disk.h>
-  #include <sys/disklabel.h>
-  #include <sys/mount.h>
+#include <sys/fdcio.h>
+#include <sys/disk.h>
+#include <sys/disklabel.h>
+#include <sys/mount.h>
 #else
-  #include <stdarg.h>
-  #include <linux/fs.h>
-  #include <linux/hdreg.h>
+#include <stdarg.h>
+#include <linux/fs.h>
+#include <linux/hdreg.h>
 #endif
 
 #include <sys/stat.h>
@@ -58,44 +58,44 @@
 #include <time.h>
 #include <unistd.h>
 
-#define MAXU16	  0xffff	/* maximum unsigned 16-bit quantity */
-#define BPN	  4		/* bits per nibble */
-#define NPB	  2		/* nibbles per byte */
+#define MAXU16   0xffff     /* maximum unsigned 16-bit quantity */
+#define BPN      4          /* bits per nibble */
+#define NPB      2          /* nibbles per byte */
 
-#define DOSMAGIC  0xaa55	/* DOS magic number */
-#define MINBPS	  512		/* minimum bytes per sector */
-#define MAXSPC	  128		/* maximum sectors per cluster */
-#define MAXNFT	  16		/* maximum number of FATs */
-#define DEFBLK	  4096		/* default block size */
-#define DEFBLK16  2048		/* default block size FAT16 */
-#define DEFRDE	  512		/* default root directory entries */
-#define RESFTE	  2		/* reserved FAT entries */
-#define MINCLS12  1		/* minimum FAT12 clusters */
-#define MINCLS16  0x1000	/* minimum FAT16 clusters */
-#define MINCLS32  2		/* minimum FAT32 clusters */
-#define MAXCLS12  0xfed 	/* maximum FAT12 clusters */
-#define MAXCLS16  0xfff5	/* maximum FAT16 clusters */
-#define MAXCLS32  0xffffff5	/* maximum FAT32 clusters */
+#define DOSMAGIC  0xaa55    /* DOS magic number */
+#define MINBPS    512       /* minimum bytes per sector */
+#define MAXSPC    128       /* maximum sectors per cluster */
+#define MAXNFT    16        /* maximum number of FATs */
+#define DEFBLK    4096      /* default block size */
+#define DEFBLK16  2048      /* default block size FAT16 */
+#define DEFRDE    512       /* default root directory entries */
+#define RESFTE    2         /* reserved FAT entries */
+#define MINCLS12  1         /* minimum FAT12 clusters */
+#define MINCLS16  0x1000    /* minimum FAT16 clusters */
+#define MINCLS32  2         /* minimum FAT32 clusters */
+#define MAXCLS12  0xfed     /* maximum FAT12 clusters */
+#define MAXCLS16  0xfff5    /* maximum FAT16 clusters */
+#define MAXCLS32  0xffffff5 /* maximum FAT32 clusters */
 
-#define mincls(fat)  ((fat) == 12 ? MINCLS12 :	\
-		      (fat) == 16 ? MINCLS16 :	\
-				    MINCLS32)
+#define mincls(fat)  ((fat) == 12 ? MINCLS12 :    \
+                      (fat) == 16 ? MINCLS16 :    \
+                                        MINCLS32)
 
-#define maxcls(fat)  ((fat) == 12 ? MAXCLS12 :	\
-		      (fat) == 16 ? MAXCLS16 :	\
-				    MAXCLS32)
+#define maxcls(fat)  ((fat) == 12 ? MAXCLS12 :    \
+                      (fat) == 16 ? MAXCLS16 :    \
+                                        MAXCLS32)
 
-#define mk1(p, x)				\
+#define mk1(p, x)                           \
     (p) = (u_int8_t)(x)
 
-#define mk2(p, x)				\
-    (p)[0] = (u_int8_t)(x),			\
+#define mk2(p, x)                           \
+    (p)[0] = (u_int8_t)(x),                 \
     (p)[1] = (u_int8_t)((x) >> 010)
 
-#define mk4(p, x)				\
-    (p)[0] = (u_int8_t)(x),			\
-    (p)[1] = (u_int8_t)((x) >> 010),		\
-    (p)[2] = (u_int8_t)((x) >> 020),		\
+#define mk4(p, x)                           \
+    (p)[0] = (u_int8_t)(x),                 \
+    (p)[1] = (u_int8_t)((x) >> 010),        \
+    (p)[2] = (u_int8_t)((x) >> 020),        \
     (p)[3] = (u_int8_t)((x) >> 030)
 
 #define argto1(arg, lo, msg)  argtou(arg, lo, 0xff, msg)
@@ -104,71 +104,71 @@
 #define argtox(arg, lo, msg)  argtou(arg, lo, UINT_MAX, msg)
 
 struct bs {
-    u_int8_t jmp[3];		/* bootstrap entry point */
-    u_int8_t oem[8];		/* OEM name and version */
+    u_int8_t jmp[3];        /* bootstrap entry point */
+    u_int8_t oem[8];        /* OEM name and version */
 };
 
 struct bsbpb {
-    u_int8_t bps[2];		/* bytes per sector */
-    u_int8_t spc;		/* sectors per cluster */
-    u_int8_t res[2];		/* reserved sectors */
-    u_int8_t nft;		/* number of FATs */
-    u_int8_t rde[2];		/* root directory entries */
-    u_int8_t sec[2];		/* total sectors */
-    u_int8_t mid;		/* media descriptor */
-    u_int8_t spf[2];		/* sectors per FAT */
-    u_int8_t spt[2];		/* sectors per track */
-    u_int8_t hds[2];		/* drive heads */
-    u_int8_t hid[4];		/* hidden sectors */
-    u_int8_t bsec[4];		/* big total sectors */
+    u_int8_t bps[2];    /* bytes per sector */
+    u_int8_t spc;       /* sectors per cluster */
+    u_int8_t res[2];    /* reserved sectors */
+    u_int8_t nft;       /* number of FATs */
+    u_int8_t rde[2];    /* root directory entries */
+    u_int8_t sec[2];    /* total sectors */
+    u_int8_t mid;       /* media descriptor */
+    u_int8_t spf[2];    /* sectors per FAT */
+    u_int8_t spt[2];    /* sectors per track */
+    u_int8_t hds[2];    /* drive heads */
+    u_int8_t hid[4];    /* hidden sectors */
+    u_int8_t bsec[4];   /* big total sectors */
 };
 
 struct bsxbpb {
-    u_int8_t bspf[4];		/* big sectors per FAT */
-    u_int8_t xflg[2];		/* FAT control flags */
-    u_int8_t vers[2];		/* file system version */
-    u_int8_t rdcl[4];		/* root directory start cluster */
-    u_int8_t infs[2];		/* file system info sector */
-    u_int8_t bkbs[2];		/* backup boot sector */
-    u_int8_t rsvd[12];		/* reserved */
+    u_int8_t bspf[4];       /* big sectors per FAT */
+    u_int8_t xflg[2];       /* FAT control flags */
+    u_int8_t vers[2];       /* file system version */
+    u_int8_t rdcl[4];       /* root directory start cluster */
+    u_int8_t infs[2];       /* file system info sector */
+    u_int8_t bkbs[2];       /* backup boot sector */
+    u_int8_t rsvd[12];      /* reserved */
 };
 
 struct bsx {
-    u_int8_t drv;		/* drive number */
-    u_int8_t rsvd;		/* reserved */
-    u_int8_t sig;		/* extended boot signature */
-    u_int8_t volid[4];		/* volume ID number */
-    u_int8_t label[11]; 	/* volume label */
-    u_int8_t type[8];		/* file system type */
+    u_int8_t drv;           /* drive number */
+    u_int8_t rsvd;          /* reserved */
+    u_int8_t sig;           /* extended boot signature */
+    u_int8_t volid[4];      /* volume ID number */
+    u_int8_t label[11];     /* volume label */
+    u_int8_t type[8];       /* file system type */
 };
 
 struct de {
-    u_int8_t namext[11];	/* name and extension */
-    u_int8_t attr;		/* attributes */
-    u_int8_t rsvd[10];		/* reserved */
-    u_int8_t time[2];		/* creation time */
-    u_int8_t date[2];		/* creation date */
-    u_int8_t clus[2];		/* starting cluster */
-    u_int8_t size[4];		/* size */
+    u_int8_t namext[11];    /* name and extension */
+    u_int8_t attr;          /* attributes */
+    u_int8_t rsvd[10];      /* reserved */
+    u_int8_t time[2];       /* creation time */
+    u_int8_t date[2];       /* creation date */
+    u_int8_t clus[2];       /* starting cluster */
+    u_int8_t size[4];       /* size */
 };
 
 struct bpb {
-    u_int bps;			/* bytes per sector */
-    u_int spc;			/* sectors per cluster */
-    u_int res;			/* reserved sectors */
-    u_int nft;			/* number of FATs */
-    u_int rde;			/* root directory entries */
-    u_int sec;			/* total sectors */
-    u_int mid;			/* media descriptor */
-    u_int spf;			/* sectors per FAT */
-    u_int spt;			/* sectors per track */
-    u_int hds;			/* drive heads */
-    u_int hid;			/* hidden sectors */
-    u_int bsec; 		/* big total sectors */
-    u_int bspf; 		/* big sectors per FAT */
-    u_int rdcl; 		/* root directory start cluster */
-    u_int infs; 		/* file system info sector */
-    u_int bkbs; 		/* backup boot sector */
+    u_int bps;          /* bytes per sector */
+    u_int spc;          /* sectors per cluster */
+    u_int res;          /* reserved sectors */
+    u_int nft;          /* number of FATs */
+    u_int rde;          /* root directory entries */
+    u_int sec;          /* total sectors */
+    u_int mid;          /* media descriptor */
+    u_int spf;          /* sectors per FAT */
+    u_int spt;          /* sectors per track */
+    u_int hds;          /* drive heads */
+    u_int hid;          /* hidden sectors */
+    u_int bsec;         /* big total sectors */
+    u_int bspf;         /* big sectors per FAT */
+    u_int rdcl;         /* root directory start cluster */
+    u_int infs;         /* file system info sector */
+    u_int bkbs;         /* backup boot sector */
 };
 
 #define BPBGAP 0, 0, 0, 0, 0, 0
@@ -181,35 +181,35 @@
     {"180",  {512, 1, 1, 2,  64,  360, 0xfc, 2,  9, 1, BPBGAP}},
     {"320",  {512, 2, 1, 2, 112,  640, 0xff, 1,  8, 2, BPBGAP}},
     {"360",  {512, 2, 1, 2, 112,  720, 0xfd, 2,  9, 2, BPBGAP}},
-    {"640",  {512, 2, 1, 2, 112, 1280, 0xfb, 2,  8, 2, BPBGAP}},    
+    {"640",  {512, 2, 1, 2, 112, 1280, 0xfb, 2,  8, 2, BPBGAP}},
     {"720",  {512, 2, 1, 2, 112, 1440, 0xf9, 3,  9, 2, BPBGAP}},
     {"1200", {512, 1, 1, 2, 224, 2400, 0xf9, 7, 15, 2, BPBGAP}},
-    {"1232", {1024,1, 1, 2, 192, 1232, 0xfe, 2,  8, 2, BPBGAP}},    
+    {"1232", {1024,1, 1, 2, 192, 1232, 0xfe, 2,  8, 2, BPBGAP}},
     {"1440", {512, 1, 1, 2, 224, 2880, 0xf0, 9, 18, 2, BPBGAP}},
     {"2880", {512, 2, 1, 2, 240, 5760, 0xf0, 9, 36, 2, BPBGAP}}
 };
 
 static const u_int8_t bootcode[] = {
-    0xfa,			/* cli		    */
-    0x31, 0xc0, 		/* xor	   ax,ax    */
-    0x8e, 0xd0, 		/* mov	   ss,ax    */
-    0xbc, 0x00, 0x7c,		/* mov	   sp,7c00h */
-    0xfb,			/* sti		    */
-    0x8e, 0xd8, 		/* mov	   ds,ax    */
-    0xe8, 0x00, 0x00,		/* call    $ + 3    */
-    0x5e,			/* pop	   si	    */
-    0x83, 0xc6, 0x19,		/* add	   si,+19h  */
-    0xbb, 0x07, 0x00,		/* mov	   bx,0007h */
-    0xfc,			/* cld		    */
-    0xac,			/* lodsb	    */
-    0x84, 0xc0, 		/* test    al,al    */
-    0x74, 0x06, 		/* jz	   $ + 8    */
-    0xb4, 0x0e, 		/* mov	   ah,0eh   */
-    0xcd, 0x10, 		/* int	   10h	    */
-    0xeb, 0xf5, 		/* jmp	   $ - 9    */
-    0x30, 0xe4, 		/* xor	   ah,ah    */
-    0xcd, 0x16, 		/* int	   16h	    */
-    0xcd, 0x19, 		/* int	   19h	    */
+    0xfa,               /* cli             */
+    0x31, 0xc0,         /* xor    ax,ax    */
+    0x8e, 0xd0,         /* mov    ss,ax    */
+    0xbc, 0x00, 0x7c,   /* mov    sp,7c00h */
+    0xfb,               /* sti             */
+    0x8e, 0xd8,         /* mov    ds,ax    */
+    0xe8, 0x00, 0x00,   /* call   $ + 3    */
+    0x5e,               /* pop    si       */
+    0x83, 0xc6, 0x19,   /* add    si,+19h  */
+    0xbb, 0x07, 0x00,   /* mov    bx,0007h */
+    0xfc,               /* cld             */
+    0xac,               /* lodsb           */
+    0x84, 0xc0,         /* test   al,al    */
+    0x74, 0x06,         /* jz     $ + 8    */
+    0xb4, 0x0e,         /* mov    ah,0eh   */
+    0xcd, 0x10,         /* int    10h      */
+    0xeb, 0xf5,         /* jmp    $ - 9    */
+    0x30, 0xe4,         /* xor    ah,ah    */
+    0xcd, 0x16,         /* int    16h      */
+    0xcd, 0x19,         /* int    19h      */
     0x0d, 0x0a,
     'N', 'o', 'n', '-', 's', 'y', 's', 't',
     'e', 'm', ' ', 'd', 'i', 's', 'k',
@@ -223,8 +223,7 @@
 
 static void check_mounted(const char *, mode_t);
 static void getstdfmt(const char *, struct bpb *);
-static void getdiskinfo(int, const char *, const char *, int,
-			struct bpb *);
+static void getdiskinfo(int, const char *, const char *, int, struct bpb *);
 static void print_bpb(struct bpb *);
 static u_int ckgeom(const char *, u_int, const char *);
 static u_int argtou(const char *, u_int, u_int, const char *);
@@ -237,14 +236,14 @@
 /*
  * Construct a FAT12, FAT16, or FAT32 file system.
  */
-int
-newfs_msdos_main(int argc, char *argv[])
+int newfs_msdos_main(int argc, char *argv[])
 {
-    static const char opts[] = "@:NB:C:F:I:L:O:S:a:b:c:e:f:h:i:k:m:n:o:r:s:u:";
+    static const char opts[] = "@:NAB:C:F:I:L:O:S:a:b:c:e:f:h:i:k:m:n:o:r:s:u:";
     const char *opt_B = NULL, *opt_L = NULL, *opt_O = NULL, *opt_f = NULL;
     u_int opt_F = 0, opt_I = 0, opt_S = 0, opt_a = 0, opt_b = 0, opt_c = 0;
     u_int opt_e = 0, opt_h = 0, opt_i = 0, opt_k = 0, opt_m = 0, opt_n = 0;
     u_int opt_o = 0, opt_r = 0, opt_s = 0, opt_u = 0;
+    u_int opt_A = 0;
     int opt_N = 0;
     int Iflag = 0, mflag = 0, oflag = 0;
     char buf[MAXPATHLEN];
@@ -262,462 +261,486 @@
     ssize_t n;
     time_t now;
     u_int fat, bss, rds, cls, dir, lsn, x, x1, x2;
+    u_int extra_res, alignment=0, set_res, set_spf, set_spc, tempx, attempts=0;
     int ch, fd, fd1;
     off_t opt_create = 0, opt_ofs = 0;
 
     while ((ch = getopt(argc, argv, opts)) != -1)
-	switch (ch) {
-	case '@':
-	    opt_ofs = argtooff(optarg, "offset");
-	    break;
-	case 'N':
-	    opt_N = 1;
-	    break;
-	case 'B':
-	    opt_B = optarg;
-	    break;
-	case 'C':
-	    opt_create = argtooff(optarg, "create size");
-	    break;
-	case 'F':
-	    if (strcmp(optarg, "12") &&
-		strcmp(optarg, "16") &&
-		strcmp(optarg, "32"))
-		errx(1, "%s: bad FAT type", optarg);
-	    opt_F = atoi(optarg);
-	    break;
-	case 'I':
-	    opt_I = argto4(optarg, 0, "volume ID");
-	    Iflag = 1;
-	    break;
-	case 'L':
-	    if (!oklabel(optarg))
-		errx(1, "%s: bad volume label", optarg);
-	    opt_L = optarg;
-	    break;
-	case 'O':
-	    if (strlen(optarg) > 8)
-		errx(1, "%s: bad OEM string", optarg);
-	    opt_O = optarg;
-	    break;
-	case 'S':
-	    opt_S = argto2(optarg, 1, "bytes/sector");
-	    break;
-	case 'a':
-	    opt_a = argto4(optarg, 1, "sectors/FAT");
-	    break;
-	case 'b':
-	    opt_b = argtox(optarg, 1, "block size");
-	    opt_c = 0;
-	    break;
-	case 'c':
-	    opt_c = argto1(optarg, 1, "sectors/cluster");
-	    opt_b = 0;
-	    break;
-	case 'e':
-	    opt_e = argto2(optarg, 1, "directory entries");
-	    break;
-	case 'f':
-	    opt_f = optarg;
-	    break;
-	case 'h':
-	    opt_h = argto2(optarg, 1, "drive heads");
-	    break;
-	case 'i':
-	    opt_i = argto2(optarg, 1, "info sector");
-	    break;
-	case 'k':
-	    opt_k = argto2(optarg, 1, "backup sector");
-	    break;
-	case 'm':
-	    opt_m = argto1(optarg, 0, "media descriptor");
-	    mflag = 1;
-	    break;
-	case 'n':
-	    opt_n = argto1(optarg, 1, "number of FATs");
-	    break;
-	case 'o':
-	    opt_o = argto4(optarg, 0, "hidden sectors");
-	    oflag = 1;
-	    break;
-	case 'r':
-	    opt_r = argto2(optarg, 1, "reserved sectors");
-	    break;
-	case 's':
-	    opt_s = argto4(optarg, 1, "file system size");
-	    break;
-	case 'u':
-	    opt_u = argto2(optarg, 1, "sectors/track");
-	    break;
-	default:
-	    usage();
-	}
+        switch (ch) {
+        case '@':
+            opt_ofs = argtooff(optarg, "offset");
+            break;
+        case 'N':
+            opt_N = 1;
+            break;
+        case 'A':
+            opt_A = 1;
+            break;
+        case 'B':
+            opt_B = optarg;
+            break;
+        case 'C':
+            opt_create = argtooff(optarg, "create size");
+            break;
+        case 'F':
+            if (strcmp(optarg, "12") &&  strcmp(optarg, "16") && strcmp(optarg, "32"))
+                errx(1, "%s: bad FAT type", optarg);
+            opt_F = atoi(optarg);
+            break;
+        case 'I':
+            opt_I = argto4(optarg, 0, "volume ID");
+            Iflag = 1;
+            break;
+        case 'L':
+            if (!oklabel(optarg))
+                errx(1, "%s: bad volume label", optarg);
+            opt_L = optarg;
+            break;
+        case 'O':
+            if (strlen(optarg) > 8)
+                errx(1, "%s: bad OEM string", optarg);
+            opt_O = optarg;
+            break;
+        case 'S':
+            opt_S = argto2(optarg, 1, "bytes/sector");
+            break;
+        case 'a':
+            opt_a = argto4(optarg, 1, "sectors/FAT");
+            break;
+        case 'b':
+            opt_b = argtox(optarg, 1, "block size");
+            opt_c = 0;
+            break;
+        case 'c':
+            opt_c = argto1(optarg, 1, "sectors/cluster");
+            opt_b = 0;
+            break;
+        case 'e':
+            opt_e = argto2(optarg, 1, "directory entries");
+            break;
+        case 'f':
+            opt_f = optarg;
+            break;
+        case 'h':
+            opt_h = argto2(optarg, 1, "drive heads");
+            break;
+        case 'i':
+            opt_i = argto2(optarg, 1, "info sector");
+            break;
+        case 'k':
+            opt_k = argto2(optarg, 1, "backup sector");
+            break;
+        case 'm':
+            opt_m = argto1(optarg, 0, "media descriptor");
+            mflag = 1;
+            break;
+        case 'n':
+            opt_n = argto1(optarg, 1, "number of FATs");
+            break;
+        case 'o':
+            opt_o = argto4(optarg, 0, "hidden sectors");
+            oflag = 1;
+            break;
+        case 'r':
+            opt_r = argto2(optarg, 1, "reserved sectors");
+            break;
+        case 's':
+            opt_s = argto4(optarg, 1, "file system size");
+            break;
+        case 'u':
+            opt_u = argto2(optarg, 1, "sectors/track");
+            break;
+        default:
+            usage();
+        }
     argc -= optind;
     argv += optind;
     if (argc < 1 || argc > 2)
-	usage();
+        usage();
     fname = *argv++;
     if (!opt_create && !strchr(fname, '/')) {
-	snprintf(buf, sizeof(buf), "%s%s", _PATH_DEV, fname);
-	if (!(fname = strdup(buf)))
-	    err(1, "%s", buf);
+        snprintf(buf, sizeof(buf), "%s%s", _PATH_DEV, fname);
+        if (!(fname = strdup(buf)))
+            err(1, "%s", buf);
     }
     dtype = *argv;
+    if (opt_A) {
+        if (opt_r)
+            errx(1, "align (-A) is incompatible with -r");
+        if (opt_N)
+            errx(1, "align (-A) is incompatible with -N");
+    }
     if (opt_create) {
-	if (opt_N)
-	    errx(1, "create (-C) is incompatible with -N");
-	fd = open(fname, O_RDWR | O_CREAT | O_TRUNC, 0644);
-	if (fd == -1)
-	    errx(1, "failed to create %s", fname);
-	if (ftruncate(fd, opt_create))
-	    errx(1, "failed to initialize %jd bytes", (intmax_t)opt_create);
+        if (opt_N)
+            errx(1, "create (-C) is incompatible with -N");
+        fd = open(fname, O_RDWR | O_CREAT | O_TRUNC, 0644);
+        if (fd == -1)
+            errx(1, "failed to create %s", fname);
+        if (ftruncate(fd, opt_create))
+            errx(1, "failed to initialize %jd bytes", (intmax_t)opt_create);
     } else if ((fd = open(fname, opt_N ? O_RDONLY : O_RDWR)) == -1)
-	err(1, "%s", fname);
+        err(1, "%s", fname);
     if (fstat(fd, &sb))
-	err(1, "%s", fname);
+        err(1, "%s", fname);
     if (opt_create) {
-	if (!S_ISREG(sb.st_mode))
-	    warnx("warning, %s is not a regular file", fname);
+        if (!S_ISREG(sb.st_mode))
+            warnx("warning, %s is not a regular file", fname);
     } else {
-	if (!S_ISCHR(sb.st_mode))
-	    warnx("warning, %s is not a character device", fname);
+        if (!S_ISCHR(sb.st_mode))
+            warnx("warning, %s is not a character device", fname);
     }
     if (!opt_N)
-	check_mounted(fname, sb.st_mode);
+        check_mounted(fname, sb.st_mode);
     if (opt_ofs && opt_ofs != lseek(fd, opt_ofs, SEEK_SET))
-	errx(1, "cannot seek to %jd", (intmax_t)opt_ofs);
+        errx(1, "cannot seek to %jd", (intmax_t)opt_ofs);
     memset(&bpb, 0, sizeof(bpb));
     if (opt_f) {
-	getstdfmt(opt_f, &bpb);
-	bpb.bsec = bpb.sec;
-	bpb.sec = 0;
-	bpb.bspf = bpb.spf;
-	bpb.spf = 0;
+        getstdfmt(opt_f, &bpb);
+        bpb.bsec = bpb.sec;
+        bpb.sec = 0;
+        bpb.bspf = bpb.spf;
+        bpb.spf = 0;
     }
     if (opt_h)
-	bpb.hds = opt_h;
+        bpb.hds = opt_h;
     if (opt_u)
-	bpb.spt = opt_u;
+        bpb.spt = opt_u;
     if (opt_S)
-	bpb.bps = opt_S;
+        bpb.bps = opt_S;
     if (opt_s)
-	bpb.bsec = opt_s;
+        bpb.bsec = opt_s;
     if (oflag)
-	bpb.hid = opt_o;
+        bpb.hid = opt_o;
     if (!(opt_f || (opt_h && opt_u && opt_S && opt_s && oflag))) {
-	off_t delta;
-	getdiskinfo(fd, fname, dtype, oflag, &bpb);
+        off_t delta;
+        getdiskinfo(fd, fname, dtype, oflag, &bpb);
         if (opt_s) {
             bpb.bsec = opt_s;
         }
-	bpb.bsec -= (opt_ofs / bpb.bps);
-	delta = bpb.bsec % bpb.spt;
-	if (delta != 0) {
-	    warnx("trim %d sectors from %d to adjust to a multiple of %d",
-		(int)delta, bpb.bsec, bpb.spt);
-	    bpb.bsec -= delta;
-	}
-	if (bpb.spc == 0) {	/* set defaults */
-	    if (bpb.bsec <= 6000)	/* about 3MB -> 512 bytes */
-		bpb.spc = 1;
-	    else if (bpb.bsec <= (1<<17)) /* 64M -> 4k */
-		bpb.spc = 8;
-	    else if (bpb.bsec <= (1<<19)) /* 256M -> 8k */
-		bpb.spc = 16;
-	    else if (bpb.bsec <= (1<<22)) /* 2G -> 16k, some versions of windows
-					     require a minimum of 65527 clusters */
-		bpb.spc = 32;
-	    else
-		bpb.spc = 64;		/* otherwise 32k */
-	}
+        bpb.bsec -= (opt_ofs / bpb.bps);
+        delta = bpb.bsec % bpb.spt;
+        if (delta != 0) {
+            warnx("trim %d sectors from %d to adjust to a multiple of %d",
+                  (int)delta, bpb.bsec, bpb.spt);
+            bpb.bsec -= delta;
+        }
+        if (bpb.spc == 0) {    /* set defaults */
+            if (bpb.bsec <= 6000)    /* about 3MB -> 512 bytes */
+                bpb.spc = 1;
+            else if (bpb.bsec <= (1<<17)) /* 64M -> 4k */
+                bpb.spc = 8;
+            else if (bpb.bsec <= (1<<19)) /* 256M -> 8k */
+                bpb.spc = 16;
+            else if (bpb.bsec <= (1<<22)) /* 2G -> 16k, some versions of windows
+                                         require a minimum of 65527 clusters */
+                bpb.spc = 32;
+            else
+                bpb.spc = 64;        /* otherwise 32k */
+        }
     }
     if (!powerof2(bpb.bps))
-	errx(1, "bytes/sector (%u) is not a power of 2", bpb.bps);
+        errx(1, "bytes/sector (%u) is not a power of 2", bpb.bps);
     if (bpb.bps < MINBPS)
-	errx(1, "bytes/sector (%u) is too small; minimum is %u",
-	     bpb.bps, MINBPS);
+        errx(1, "bytes/sector (%u) is too small; minimum is %u",
+             bpb.bps, MINBPS);
     if (!(fat = opt_F)) {
-	if (opt_f)
-	    fat = 12;
-	else if (!opt_e && (opt_i || opt_k))
-	    fat = 32;
+        if (opt_f)
+            fat = 12;
+        else if (!opt_e && (opt_i || opt_k))
+            fat = 32;
     }
     if ((fat == 32 && opt_e) || (fat != 32 && (opt_i || opt_k)))
-	errx(1, "-%c is not a legal FAT%s option",
-	     fat == 32 ? 'e' : opt_i ? 'i' : 'k',
-	     fat == 32 ? "32" : "12/16");
+        errx(1, "-%c is not a legal FAT%s option",
+             fat == 32 ? 'e' : opt_i ? 'i' : 'k',
+                     fat == 32 ? "32" : "12/16");
     if (opt_f && fat == 32)
-	bpb.rde = 0;
+        bpb.rde = 0;
     if (opt_b) {
-	if (!powerof2(opt_b))
-	    errx(1, "block size (%u) is not a power of 2", opt_b);
-	if (opt_b < bpb.bps)
-	    errx(1, "block size (%u) is too small; minimum is %u",
-		 opt_b, bpb.bps);
-	if (opt_b > bpb.bps * MAXSPC)
-	    errx(1, "block size (%u) is too large; maximum is %u",
-		 opt_b, bpb.bps * MAXSPC);
-	bpb.spc = opt_b / bpb.bps;
+        if (!powerof2(opt_b))
+            errx(1, "block size (%u) is not a power of 2", opt_b);
+        if (opt_b < bpb.bps)
+            errx(1, "block size (%u) is too small; minimum is %u",
+                 opt_b, bpb.bps);
+        if (opt_b > bpb.bps * MAXSPC)
+            errx(1, "block size (%u) is too large; maximum is %u", opt_b, bpb.bps * MAXSPC);
+        bpb.spc = opt_b / bpb.bps;
     }
     if (opt_c) {
-	if (!powerof2(opt_c))
-	    errx(1, "sectors/cluster (%u) is not a power of 2", opt_c);
-	bpb.spc = opt_c;
+        if (!powerof2(opt_c))
+            errx(1, "sectors/cluster (%u) is not a power of 2", opt_c);
+        bpb.spc = opt_c;
     }
     if (opt_r)
-	bpb.res = opt_r;
+        bpb.res = opt_r;
     if (opt_n) {
-	if (opt_n > MAXNFT)
-	    errx(1, "number of FATs (%u) is too large; maximum is %u",
-		 opt_n, MAXNFT);
-	bpb.nft = opt_n;
+        if (opt_n > MAXNFT)
+            errx(1, "number of FATs (%u) is too large; maximum is %u", opt_n, MAXNFT);
+        bpb.nft = opt_n;
     }
     if (opt_e)
-	bpb.rde = opt_e;
+        bpb.rde = opt_e;
     if (mflag) {
-	if (opt_m < 0xf0)
-	    errx(1, "illegal media descriptor (%#x)", opt_m);
-	bpb.mid = opt_m;
+        if (opt_m < 0xf0)
+            errx(1, "illegal media descriptor (%#x)", opt_m);
+        bpb.mid = opt_m;
     }
     if (opt_a)
-	bpb.bspf = opt_a;
+        bpb.bspf = opt_a;
     if (opt_i)
-	bpb.infs = opt_i;
+        bpb.infs = opt_i;
     if (opt_k)
-	bpb.bkbs = opt_k;
+        bpb.bkbs = opt_k;
     bss = 1;
     bname = NULL;
     fd1 = -1;
     if (opt_B) {
-	bname = opt_B;
-	if (!strchr(bname, '/')) {
-	    snprintf(buf, sizeof(buf), "/boot/%s", bname);
-	    if (!(bname = strdup(buf)))
-		err(1, "%s", buf);
-	}
-	if ((fd1 = open(bname, O_RDONLY)) == -1 || fstat(fd1, &sb))
-	    err(1, "%s", bname);
-	if (!S_ISREG(sb.st_mode) || sb.st_size % bpb.bps ||
-	    sb.st_size < bpb.bps || sb.st_size > bpb.bps * MAXU16)
-	    errx(1, "%s: inappropriate file type or format", bname);
-	bss = sb.st_size / bpb.bps;
+        bname = opt_B;
+        if (!strchr(bname, '/')) {
+            snprintf(buf, sizeof(buf), "/boot/%s", bname);
+            if (!(bname = strdup(buf)))
+                err(1, "%s", buf);
+        }
+        if ((fd1 = open(bname, O_RDONLY)) == -1 || fstat(fd1, &sb))
+            err(1, "%s", bname);
+        if (!S_ISREG(sb.st_mode) || sb.st_size % bpb.bps ||
+                sb.st_size < bpb.bps || sb.st_size > bpb.bps * MAXU16)
+            errx(1, "%s: inappropriate file type or format", bname);
+        bss = sb.st_size / bpb.bps;
     }
     if (!bpb.nft)
-	bpb.nft = 2;
+        bpb.nft = 2;
     if (!fat) {
-	if (bpb.bsec < (bpb.res ? bpb.res : bss) +
-	    howmany((RESFTE + (bpb.spc ? MINCLS16 : MAXCLS12 + 1)) *
-		    ((bpb.spc ? 16 : 12) / BPN), bpb.bps * NPB) *
-	    bpb.nft +
-	    howmany(bpb.rde ? bpb.rde : DEFRDE,
-		    bpb.bps / sizeof(struct de)) +
-	    (bpb.spc ? MINCLS16 : MAXCLS12 + 1) *
-	    (bpb.spc ? bpb.spc : howmany(DEFBLK, bpb.bps)))
-	    fat = 12;
-	else if (bpb.rde || bpb.bsec <
-		 (bpb.res ? bpb.res : bss) +
-		 howmany((RESFTE + MAXCLS16) * 2, bpb.bps) * bpb.nft +
-		 howmany(DEFRDE, bpb.bps / sizeof(struct de)) +
-		 (MAXCLS16 + 1) *
-		 (bpb.spc ? bpb.spc : howmany(8192, bpb.bps)))
-	    fat = 16;
-	else
-	    fat = 32;
+        if (bpb.bsec < (bpb.res ? bpb.res : bss) +
+                howmany((RESFTE + (bpb.spc ? MINCLS16 : MAXCLS12 + 1)) *
+                        ((bpb.spc ? 16 : 12) / BPN), bpb.bps * NPB) *
+                        bpb.nft +
+                        howmany(bpb.rde ? bpb.rde : DEFRDE,
+                                bpb.bps / sizeof(struct de)) +
+                                (bpb.spc ? MINCLS16 : MAXCLS12 + 1) *
+                                (bpb.spc ? bpb.spc : howmany(DEFBLK, bpb.bps)))
+            fat = 12;
+        else if (bpb.rde || bpb.bsec <
+                (bpb.res ? bpb.res : bss) +
+                howmany((RESFTE + MAXCLS16) * 2, bpb.bps) * bpb.nft +
+                howmany(DEFRDE, bpb.bps / sizeof(struct de)) +
+                (MAXCLS16 + 1) *
+                (bpb.spc ? bpb.spc : howmany(8192, bpb.bps)))
+            fat = 16;
+        else
+            fat = 32;
     }
     x = bss;
     if (fat == 32) {
-	if (!bpb.infs) {
-	    if (x == MAXU16 || x == bpb.bkbs)
-		errx(1, "no room for info sector");
-	    bpb.infs = x;
-	}
-	if (bpb.infs != MAXU16 && x <= bpb.infs)
-	    x = bpb.infs + 1;
-	if (!bpb.bkbs) {
-	    if (x == MAXU16)
-		errx(1, "no room for backup sector");
-	    bpb.bkbs = x;
-	} else if (bpb.bkbs != MAXU16 && bpb.bkbs == bpb.infs)
-	    errx(1, "backup sector would overwrite info sector");
-	if (bpb.bkbs != MAXU16 && x <= bpb.bkbs)
-	    x = bpb.bkbs + 1;
+        if (!bpb.infs) {
+            if (x == MAXU16 || x == bpb.bkbs)
+                errx(1, "no room for info sector");
+            bpb.infs = x;
+        }
+        if (bpb.infs != MAXU16 && x <= bpb.infs)
+            x = bpb.infs + 1;
+        if (!bpb.bkbs) {
+            if (x == MAXU16)
+                errx(1, "no room for backup sector");
+            bpb.bkbs = x;
+        } else if (bpb.bkbs != MAXU16 && bpb.bkbs == bpb.infs)
+            errx(1, "backup sector would overwrite info sector");
+        if (bpb.bkbs != MAXU16 && x <= bpb.bkbs)
+            x = bpb.bkbs + 1;
     }
-    if (!bpb.res)
-	bpb.res = fat == 32 ? MAX(x, MAX(16384 / bpb.bps, 4)) : x;
-    else if (bpb.res < x)
-	errx(1, "too few reserved sectors");
-    if (fat != 32 && !bpb.rde)
-	bpb.rde = DEFRDE;
-    rds = howmany(bpb.rde, bpb.bps / sizeof(struct de));
-    if (!bpb.spc)
-	for (bpb.spc = howmany(fat == 16 ? DEFBLK16 : DEFBLK, bpb.bps);
-	     bpb.spc < MAXSPC &&
-	     bpb.res +
-	     howmany((RESFTE + maxcls(fat)) * (fat / BPN),
-		     bpb.bps * NPB) * bpb.nft +
-	     rds +
-	     (u_int64_t)(maxcls(fat) + 1) * bpb.spc <= bpb.bsec;
-	     bpb.spc <<= 1);
-    if (fat != 32 && bpb.bspf > MAXU16)
-	errx(1, "too many sectors/FAT for FAT12/16");
-    x1 = bpb.res + rds;
-    x = bpb.bspf ? bpb.bspf : 1;
-    if (x1 + (u_int64_t)x * bpb.nft > bpb.bsec)
-	errx(1, "meta data exceeds file system size");
-    x1 += x * bpb.nft;
-    x = (u_int64_t)(bpb.bsec - x1) * bpb.bps * NPB /
-	(bpb.spc * bpb.bps * NPB + fat / BPN * bpb.nft);
-    x2 = howmany((RESFTE + MIN(x, maxcls(fat))) * (fat / BPN),
-		 bpb.bps * NPB);
-    if (!bpb.bspf) {
-	bpb.bspf = x2;
-	x1 += (bpb.bspf - 1) * bpb.nft;
-    }
+
+    extra_res = 0;
+    set_res = !bpb.res;
+    set_spf = !bpb.bspf;
+    set_spc = !bpb.spc;
+    tempx = x;
+    /*
+     * Attempt to align if opt_A is set. This is done by increasing the number
+     * of reserved blocks. This can cause other factors to change, which can in
+     * turn change the alignment. This should take at most 2 iterations, as
+     * increasing the reserved amount may cause the FAT size to decrease by 1,
+     * requiring another nft reserved blocks. If spc changes, it will
+     * be half of its previous size, and thus will not throw off alignment.
+     */
+    do {
+        x = tempx;
+        if (set_res)
+            bpb.res = (fat == 32 ? MAX(x, MAX(16384 / bpb.bps, 4)) : x) + extra_res;
+        else if (bpb.res < x)
+            errx(1, "too few reserved sectors");
+        if (fat != 32 && !bpb.rde)
+            bpb.rde = DEFRDE;
+        rds = howmany(bpb.rde, bpb.bps / sizeof(struct de));
+        if (set_spc)
+            for (bpb.spc = howmany(fat == 16 ? DEFBLK16 : DEFBLK, bpb.bps);
+                    bpb.spc < MAXSPC &&
+                    bpb.res +
+                    howmany((RESFTE + maxcls(fat)) * (fat / BPN),
+                            bpb.bps * NPB) * bpb.nft +
+                            rds +
+                            (u_int64_t)(maxcls(fat) + 1) * bpb.spc <= bpb.bsec;
+                    bpb.spc <<= 1);
+        if (fat != 32 && bpb.bspf > MAXU16)
+            errx(1, "too many sectors/FAT for FAT12/16");
+        x1 = bpb.res + rds;
+        x = bpb.bspf ? bpb.bspf : 1;
+        if (x1 + (u_int64_t)x * bpb.nft > bpb.bsec)
+            errx(1, "meta data exceeds file system size");
+        x1 += x * bpb.nft;
+        x = (u_int64_t)(bpb.bsec - x1) * bpb.bps * NPB /
+                (bpb.spc * bpb.bps * NPB + fat / BPN * bpb.nft);
+        x2 = howmany((RESFTE + MIN(x, maxcls(fat))) * (fat / BPN), bpb.bps * NPB);
+        if (set_spf) {
+            if (!bpb.bspf) {
+                bpb.bspf = x2;
+            }
+            x1 += (bpb.bspf - 1) * bpb.nft;
+        }
+        if(set_res) {
+            /* attempt to align root directory */
+            alignment = (bpb.res + bpb.bspf * bpb.nft) % bpb.spc;
+            extra_res += bpb.spc - alignment;
+        }
+        attempts++;
+    } while(opt_A && alignment != 0 && attempts < 2);
+    if (alignment != 0)
+        warnx("warning: Alignment failed.");
+
     cls = (bpb.bsec - x1) / bpb.spc;
     x = (u_int64_t)bpb.bspf * bpb.bps * NPB / (fat / BPN) - RESFTE;
     if (cls > x)
-	cls = x;
+        cls = x;
     if (bpb.bspf < x2)
-	warnx("warning: sectors/FAT limits file system to %u clusters",
-	      cls);
+        warnx("warning: sectors/FAT limits file system to %u clusters", cls);
     if (cls < mincls(fat))
-	errx(1, "%u clusters too few clusters for FAT%u, need %u", cls, fat,
-	    mincls(fat));
+        errx(1, "%u clusters too few clusters for FAT%u, need %u", cls, fat, mincls(fat));
     if (cls > maxcls(fat)) {
-	cls = maxcls(fat);
-	bpb.bsec = x1 + (cls + 1) * bpb.spc - 1;
-	warnx("warning: FAT type limits file system to %u sectors",
-	      bpb.bsec);
+        cls = maxcls(fat);
+        bpb.bsec = x1 + (cls + 1) * bpb.spc - 1;
+        warnx("warning: FAT type limits file system to %u sectors", bpb.bsec);
     }
-    printf("%s: %u sector%s in %u FAT%u cluster%s "
-	   "(%u bytes/cluster)\n", fname, cls * bpb.spc,
-	   cls * bpb.spc == 1 ? "" : "s", cls, fat,
-	   cls == 1 ? "" : "s", bpb.bps * bpb.spc);
+    printf("%s: %u sector%s in %u FAT%u cluster%s (%u bytes/cluster)\n",
+           fname, cls * bpb.spc, cls * bpb.spc == 1 ? "" : "s", cls, fat,
+           cls == 1 ? "" : "s", bpb.bps * bpb.spc);
     if (!bpb.mid)
-	bpb.mid = !bpb.hid ? 0xf0 : 0xf8;
+        bpb.mid = !bpb.hid ? 0xf0 : 0xf8;
     if (fat == 32)
-	bpb.rdcl = RESFTE;
+        bpb.rdcl = RESFTE;
     if (bpb.hid + bpb.bsec <= MAXU16) {
-	bpb.sec = bpb.bsec;
-	bpb.bsec = 0;
+        bpb.sec = bpb.bsec;
+        bpb.bsec = 0;
     }
     if (fat != 32) {
-	bpb.spf = bpb.bspf;
-	bpb.bspf = 0;
+        bpb.spf = bpb.bspf;
+        bpb.bspf = 0;
     }
     print_bpb(&bpb);
     if (!opt_N) {
-	gettimeofday(&tv, NULL);
-	now = tv.tv_sec;
-	tm = localtime(&now);
-	if (!(img = malloc(bpb.bps)))
-	    err(1, "%u", bpb.bps);
-	dir = bpb.res + (bpb.spf ? bpb.spf : bpb.bspf) * bpb.nft;
-	for (lsn = 0; lsn < dir + (fat == 32 ? bpb.spc : rds); lsn++) {
-	    x = lsn;
-	    if (opt_B &&
-		fat == 32 && bpb.bkbs != MAXU16 &&
-		bss <= bpb.bkbs && x >= bpb.bkbs) {
-		x -= bpb.bkbs;
-		if (!x && lseek(fd1, opt_ofs, SEEK_SET))
-		    err(1, "%s", bname);
-	    }
-	    if (opt_B && x < bss) {
-		if ((n = read(fd1, img, bpb.bps)) == -1)
-		    err(1, "%s", bname);
-		if ((unsigned)n != bpb.bps)
-		    errx(1, "%s: can't read sector %u", bname, x);
-	    } else
-		memset(img, 0, bpb.bps);
-	    if (!lsn ||
-	      (fat == 32 && bpb.bkbs != MAXU16 && lsn == bpb.bkbs)) {
-		x1 = sizeof(struct bs);
-		bsbpb = (struct bsbpb *)(img + x1);
-		mk2(bsbpb->bps, bpb.bps);
-		mk1(bsbpb->spc, bpb.spc);
-		mk2(bsbpb->res, bpb.res);
-		mk1(bsbpb->nft, bpb.nft);
-		mk2(bsbpb->rde, bpb.rde);
-		mk2(bsbpb->sec, bpb.sec);
-		mk1(bsbpb->mid, bpb.mid);
-		mk2(bsbpb->spf, bpb.spf);
-		mk2(bsbpb->spt, bpb.spt);
-		mk2(bsbpb->hds, bpb.hds);
-		mk4(bsbpb->hid, bpb.hid);
-		mk4(bsbpb->bsec, bpb.bsec);
-		x1 += sizeof(struct bsbpb);
-		if (fat == 32) {
-		    bsxbpb = (struct bsxbpb *)(img + x1);
-		    mk4(bsxbpb->bspf, bpb.bspf);
-		    mk2(bsxbpb->xflg, 0);
-		    mk2(bsxbpb->vers, 0);
-		    mk4(bsxbpb->rdcl, bpb.rdcl);
-		    mk2(bsxbpb->infs, bpb.infs);
-		    mk2(bsxbpb->bkbs, bpb.bkbs);
-		    x1 += sizeof(struct bsxbpb);
-		}
-		bsx = (struct bsx *)(img + x1);
-		mk1(bsx->sig, 0x29);
-		if (Iflag)
-		    x = opt_I;
-		else
-		    x = (((u_int)(1 + tm->tm_mon) << 8 |
-			  (u_int)tm->tm_mday) +
-			 ((u_int)tm->tm_sec << 8 |
-			  (u_int)(tv.tv_usec / 10))) << 16 |
-			((u_int)(1900 + tm->tm_year) +
-			 ((u_int)tm->tm_hour << 8 |
-			  (u_int)tm->tm_min));
-		mk4(bsx->volid, x);
-		mklabel(bsx->label, opt_L ? opt_L : "NO NAME");
-		sprintf(buf, "FAT%u", fat);
-		setstr(bsx->type, buf, sizeof(bsx->type));
-		if (!opt_B) {
-		    x1 += sizeof(struct bsx);
-		    bs = (struct bs *)img;
-		    mk1(bs->jmp[0], 0xeb);
-		    mk1(bs->jmp[1], x1 - 2);
-		    mk1(bs->jmp[2], 0x90);
-		    setstr(bs->oem, opt_O ? opt_O : "BSD  4.4",
-			   sizeof(bs->oem));
-		    memcpy(img + x1, bootcode, sizeof(bootcode));
-		    mk2(img + MINBPS - 2, DOSMAGIC);
-		}
-	    } else if (fat == 32 && bpb.infs != MAXU16 &&
-		       (lsn == bpb.infs ||
-			(bpb.bkbs != MAXU16 &&
-			 lsn == bpb.bkbs + bpb.infs))) {
-		mk4(img, 0x41615252);
-		mk4(img + MINBPS - 28, 0x61417272);
-		mk4(img + MINBPS - 24, 0xffffffff);
-		mk4(img + MINBPS - 20, bpb.rdcl);
-		mk2(img + MINBPS - 2, DOSMAGIC);
-	    } else if (lsn >= bpb.res && lsn < dir &&
-		       !((lsn - bpb.res) %
-			 (bpb.spf ? bpb.spf : bpb.bspf))) {
-		mk1(img[0], bpb.mid);
-		for (x = 1; x < fat * (fat == 32 ? 3 : 2) / 8; x++)
-		    mk1(img[x], fat == 32 && x % 4 == 3 ? 0x0f : 0xff);
-	    } else if (lsn == dir && opt_L) {
-		de = (struct de *)img;
-		mklabel(de->namext, opt_L);
-		mk1(de->attr, 050);
-		x = (u_int)tm->tm_hour << 11 |
-		    (u_int)tm->tm_min << 5 |
-		    (u_int)tm->tm_sec >> 1;
-		mk2(de->time, x);
-		x = (u_int)(tm->tm_year - 80) << 9 |
-		    (u_int)(tm->tm_mon + 1) << 5 |
-		    (u_int)tm->tm_mday;
-		mk2(de->date, x);
-	    }
-	    if ((n = write(fd, img, bpb.bps)) == -1)
-		err(1, "%s", fname);
-	    if ((unsigned)n != bpb.bps) {
-		errx(1, "%s: can't write sector %u", fname, lsn);
+        gettimeofday(&tv, NULL);
+        now = tv.tv_sec;
+        tm = localtime(&now);
+        if (!(img = malloc(bpb.bps)))
+            err(1, "%u", bpb.bps);
+        dir = bpb.res + (bpb.spf ? bpb.spf : bpb.bspf) * bpb.nft;
+        for (lsn = 0; lsn < dir + (fat == 32 ? bpb.spc : rds); lsn++) {
+            x = lsn;
+            if (opt_B && fat == 32 && bpb.bkbs != MAXU16 && bss <= bpb.bkbs && x >= bpb.bkbs) {
+                x -= bpb.bkbs;
+                if (!x && lseek(fd1, opt_ofs, SEEK_SET))
+                    err(1, "%s", bname);
+            }
+            if (opt_B && x < bss) {
+                if ((n = read(fd1, img, bpb.bps)) == -1)
+                    err(1, "%s", bname);
+                if ((unsigned)n != bpb.bps)
+                    errx(1, "%s: can't read sector %u", bname, x);
+            } else
+                memset(img, 0, bpb.bps);
+            if (!lsn || (fat == 32 && bpb.bkbs != MAXU16 && lsn == bpb.bkbs)) {
+                x1 = sizeof(struct bs);
+                bsbpb = (struct bsbpb *)(img + x1);
+                mk2(bsbpb->bps, bpb.bps);
+                mk1(bsbpb->spc, bpb.spc);
+                mk2(bsbpb->res, bpb.res);
+                mk1(bsbpb->nft, bpb.nft);
+                mk2(bsbpb->rde, bpb.rde);
+                mk2(bsbpb->sec, bpb.sec);
+                mk1(bsbpb->mid, bpb.mid);
+                mk2(bsbpb->spf, bpb.spf);
+                mk2(bsbpb->spt, bpb.spt);
+                mk2(bsbpb->hds, bpb.hds);
+                mk4(bsbpb->hid, bpb.hid);
+                mk4(bsbpb->bsec, bpb.bsec);
+                x1 += sizeof(struct bsbpb);
+                if (fat == 32) {
+                    bsxbpb = (struct bsxbpb *)(img + x1);
+                    mk4(bsxbpb->bspf, bpb.bspf);
+                    mk2(bsxbpb->xflg, 0);
+                    mk2(bsxbpb->vers, 0);
+                    mk4(bsxbpb->rdcl, bpb.rdcl);
+                    mk2(bsxbpb->infs, bpb.infs);
+                    mk2(bsxbpb->bkbs, bpb.bkbs);
+                    x1 += sizeof(struct bsxbpb);
+                }
+                bsx = (struct bsx *)(img + x1);
+                mk1(bsx->sig, 0x29);
+                if (Iflag)
+                    x = opt_I;
+                else
+                    x = (((u_int)(1 + tm->tm_mon) << 8 |
+                            (u_int)tm->tm_mday) +
+                            ((u_int)tm->tm_sec << 8 |
+                                    (u_int)(tv.tv_usec / 10))) << 16 |
+                                    ((u_int)(1900 + tm->tm_year) +
+                                            ((u_int)tm->tm_hour << 8 |
+                                                    (u_int)tm->tm_min));
+                mk4(bsx->volid, x);
+                mklabel(bsx->label, opt_L ? opt_L : "NO NAME");
+                sprintf(buf, "FAT%u", fat);
+                setstr(bsx->type, buf, sizeof(bsx->type));
+                if (!opt_B) {
+                    x1 += sizeof(struct bsx);
+                    bs = (struct bs *)img;
+                    mk1(bs->jmp[0], 0xeb);
+                    mk1(bs->jmp[1], x1 - 2);
+                    mk1(bs->jmp[2], 0x90);
+                    setstr(bs->oem, opt_O ? opt_O : "BSD  4.4",
+                            sizeof(bs->oem));
+                    memcpy(img + x1, bootcode, sizeof(bootcode));
+                    mk2(img + MINBPS - 2, DOSMAGIC);
+                }
+            } else if (fat == 32 && bpb.infs != MAXU16 &&
+                    (lsn == bpb.infs || (bpb.bkbs != MAXU16 &&
+                                    lsn == bpb.bkbs + bpb.infs))) {
+                mk4(img, 0x41615252);
+                mk4(img + MINBPS - 28, 0x61417272);
+                mk4(img + MINBPS - 24, 0xffffffff);
+                mk4(img + MINBPS - 20, bpb.rdcl);
+                mk2(img + MINBPS - 2, DOSMAGIC);
+            } else if (lsn >= bpb.res && lsn < dir &&
+                    !((lsn - bpb.res) % (bpb.spf ? bpb.spf : bpb.bspf))) {
+                mk1(img[0], bpb.mid);
+                for (x = 1; x < fat * (fat == 32 ? 3 : 2) / 8; x++)
+                    mk1(img[x], fat == 32 && x % 4 == 3 ? 0x0f : 0xff);
+            } else if (lsn == dir && opt_L) {
+                de = (struct de *)img;
+                mklabel(de->namext, opt_L);
+                mk1(de->attr, 050);
+                x = (u_int)tm->tm_hour << 11 |
+                        (u_int)tm->tm_min << 5 |
+                        (u_int)tm->tm_sec >> 1;
+                mk2(de->time, x);
+                x = (u_int)(tm->tm_year - 80) << 9 |
+                        (u_int)(tm->tm_mon + 1) << 5 |
+                        (u_int)tm->tm_mday;
+                mk2(de->date, x);
+            }
+            if ((n = write(fd, img, bpb.bps)) == -1)
+                err(1, "%s", fname);
+            if ((unsigned)n != bpb.bps) {
+                errx(1, "%s: can't write sector %u", fname, lsn);
                 exit(1);
             }
-	}
+        }
     }
     return 0;
 }
@@ -725,8 +748,7 @@
 /*
  * Exit with error if file system is mounted.
  */
-static void
-check_mounted(const char *fname, mode_t mode)
+static void check_mounted(const char *fname, mode_t mode)
 {
 #ifdef ANDROID
     warnx("Skipping mount checks");
@@ -737,19 +759,18 @@
     int n, r;
 
     if (!(n = getmntinfo(&mp, MNT_NOWAIT)))
-	err(1, "getmntinfo");
+        err(1, "getmntinfo");
     len = strlen(_PATH_DEV);
     s1 = fname;
     if (!strncmp(s1, _PATH_DEV, len))
-	s1 += len;
+        s1 += len;
     r = S_ISCHR(mode) && s1 != fname && *s1 == 'r';
     for (; n--; mp++) {
-	s2 = mp->f_mntfromname;
-	if (!strncmp(s2, _PATH_DEV, len))
-	    s2 += len;
-	if ((r && s2 != mp->f_mntfromname && !strcmp(s1 + 1, s2)) ||
-	    !strcmp(s1, s2))
-	    errx(1, "%s is mounted on %s", fname, mp->f_mntonname);
+        s2 = mp->f_mntfromname;
+        if (!strncmp(s2, _PATH_DEV, len))
+            s2 += len;
+        if ((r && s2 != mp->f_mntfromname && !strcmp(s1 + 1, s2)) || !strcmp(s1, s2))
+            errx(1, "%s is mounted on %s", fname, mp->f_mntonname);
     }
 #endif
 }
@@ -757,15 +778,14 @@
 /*
  * Get a standard format.
  */
-static void
-getstdfmt(const char *fmt, struct bpb *bpb)
+static void getstdfmt(const char *fmt, struct bpb *bpb)
 {
     u_int x, i;
 
     x = sizeof(stdfmt) / sizeof(stdfmt[0]);
     for (i = 0; i < x && strcmp(fmt, stdfmt[i].name); i++);
     if (i == x)
-	errx(1, "%s: unknown standard format", fmt);
+        errx(1, "%s: unknown standard format", fmt);
     *bpb = stdfmt[i].bpb;
 }
 
@@ -774,9 +794,8 @@
  */
 
 #ifdef ANDROID
-static void
-getdiskinfo(int fd, const char *fname, const char *dtype, __unused int oflag,
-	    struct bpb *bpb)
+static void getdiskinfo(int fd, const char *fname, const char *dtype,
+                        __unused int oflag,struct bpb *bpb)
 {
     struct hd_geometry geom;
 
@@ -817,9 +836,8 @@
 
 #else
 
-static void
-getdiskinfo(int fd, const char *fname, const char *dtype, __unused int oflag,
-	    struct bpb *bpb)
+static void getdiskinfo(int fd, const char *fname, const char *dtype,
+                        __unused int oflag, struct bpb *bpb)
 {
     struct disklabel *lp, dlp;
     struct fd_type type;
@@ -829,97 +847,96 @@
 
     /* If the user specified a disk type, try to use that */
     if (dtype != NULL) {
-	lp = getdiskbyname(dtype);
+        lp = getdiskbyname(dtype);
     }
 
     /* Maybe it's a floppy drive */
     if (lp == NULL) {
-	if (ioctl(fd, DIOCGMEDIASIZE, &ms) == -1) {
-	    struct stat st;
+        if (ioctl(fd, DIOCGMEDIASIZE, &ms) == -1) {
+            struct stat st;
 
-	    if (fstat(fd, &st))
-		err(1, "Cannot get disk size");
-	    /* create a fake geometry for a file image */
-	    ms = st.st_size;
-	    dlp.d_secsize = 512;
-	    dlp.d_nsectors = 63;
-	    dlp.d_ntracks = 255;
-	    dlp.d_secperunit = ms / dlp.d_secsize;
-	    lp = &dlp;
-	} else if (ioctl(fd, FD_GTYPE, &type) != -1) {
-	    dlp.d_secsize = 128 << type.secsize;
-	    dlp.d_nsectors = type.sectrac;
-	    dlp.d_ntracks = type.heads;
-	    dlp.d_secperunit = ms / dlp.d_secsize;
-	    lp = &dlp;
-	}
+            if (fstat(fd, &st))
+                err(1, "Cannot get disk size");
+            /* create a fake geometry for a file image */
+            ms = st.st_size;
+            dlp.d_secsize = 512;
+            dlp.d_nsectors = 63;
+            dlp.d_ntracks = 255;
+            dlp.d_secperunit = ms / dlp.d_secsize;
+            lp = &dlp;
+        } else if (ioctl(fd, FD_GTYPE, &type) != -1) {
+            dlp.d_secsize = 128 << type.secsize;
+            dlp.d_nsectors = type.sectrac;
+            dlp.d_ntracks = type.heads;
+            dlp.d_secperunit = ms / dlp.d_secsize;
+            lp = &dlp;
+        }
     }
 
     /* Maybe it's a fixed drive */
     if (lp == NULL) {
-	if (ioctl(fd, DIOCGDINFO, &dlp) == -1) {
-	    if (bpb->bps == 0 && ioctl(fd, DIOCGSECTORSIZE, &dlp.d_secsize) == -1)
-		errx(1, "Cannot get sector size, %s", strerror(errno));
+        if (ioctl(fd, DIOCGDINFO, &dlp) == -1) {
+            if (bpb->bps == 0 && ioctl(fd, DIOCGSECTORSIZE, &dlp.d_secsize) == -1)
+                errx(1, "Cannot get sector size, %s", strerror(errno));
 
-	    /* XXX Should we use bpb->bps if it's set? */
-	    dlp.d_secperunit = ms / dlp.d_secsize;
+            /* XXX Should we use bpb->bps if it's set? */
+            dlp.d_secperunit = ms / dlp.d_secsize;
 
-	    if (bpb->spt == 0 && ioctl(fd, DIOCGFWSECTORS, &dlp.d_nsectors) == -1) {
-		warnx("Cannot get number of sectors per track, %s", strerror(errno));
-		dlp.d_nsectors = 63;
-	    }
-	    if (bpb->hds == 0 && ioctl(fd, DIOCGFWHEADS, &dlp.d_ntracks) == -1) {
-		warnx("Cannot get number of heads, %s", strerror(errno));
-		if (dlp.d_secperunit <= 63*1*1024)
-		    dlp.d_ntracks = 1;
-		else if (dlp.d_secperunit <= 63*16*1024)
-		    dlp.d_ntracks = 16;
-		else
-		    dlp.d_ntracks = 255;
-	    }
-	}
+            if (bpb->spt == 0 && ioctl(fd, DIOCGFWSECTORS, &dlp.d_nsectors) == -1) {
+                warnx("Cannot get number of sectors per track, %s", strerror(errno));
+                dlp.d_nsectors = 63;
+            }
+            if (bpb->hds == 0 && ioctl(fd, DIOCGFWHEADS, &dlp.d_ntracks) == -1) {
+                warnx("Cannot get number of heads, %s", strerror(errno));
+                if (dlp.d_secperunit <= 63*1*1024)
+                    dlp.d_ntracks = 1;
+                else if (dlp.d_secperunit <= 63*16*1024)
+                    dlp.d_ntracks = 16;
+                else
+                    dlp.d_ntracks = 255;
+            }
+        }
 
-	hs = (ms / dlp.d_secsize) - dlp.d_secperunit;
-	lp = &dlp;
+        hs = (ms / dlp.d_secsize) - dlp.d_secperunit;
+        lp = &dlp;
     }
 
     if (bpb->bps == 0)
-	bpb->bps = ckgeom(fname, lp->d_secsize, "bytes/sector");
+        bpb->bps = ckgeom(fname, lp->d_secsize, "bytes/sector");
     if (bpb->spt == 0)
-	bpb->spt = ckgeom(fname, lp->d_nsectors, "sectors/track");
+        bpb->spt = ckgeom(fname, lp->d_nsectors, "sectors/track");
     if (bpb->hds == 0)
-	bpb->hds = ckgeom(fname, lp->d_ntracks, "drive heads");
+        bpb->hds = ckgeom(fname, lp->d_ntracks, "drive heads");
     if (bpb->bsec == 0)
-	bpb->bsec = lp->d_secperunit;
+        bpb->bsec = lp->d_secperunit;
     if (bpb->hid == 0)
-	bpb->hid = hs;
+        bpb->hid = hs;
 }
 #endif
 
 /*
  * Print out BPB values.
  */
-static void
-print_bpb(struct bpb *bpb)
+static void print_bpb(struct bpb *bpb)
 {
     printf("bps=%u spc=%u res=%u nft=%u", bpb->bps, bpb->spc, bpb->res,
-	   bpb->nft);
+           bpb->nft);
     if (bpb->rde)
-	printf(" rde=%u", bpb->rde);
+        printf(" rde=%u", bpb->rde);
     if (bpb->sec)
-	printf(" sec=%u", bpb->sec);
+        printf(" sec=%u", bpb->sec);
     printf(" mid=%#x", bpb->mid);
     if (bpb->spf)
-	printf(" spf=%u", bpb->spf);
+        printf(" spf=%u", bpb->spf);
     printf(" spt=%u hds=%u hid=%u", bpb->spt, bpb->hds, bpb->hid);
     if (bpb->bsec)
-	printf(" bsec=%u", bpb->bsec);
+        printf(" bsec=%u", bpb->bsec);
     if (!bpb->spf) {
-	printf(" bspf=%u rdcl=%u", bpb->bspf, bpb->rdcl);
-	printf(" infs=");
-	printf(bpb->infs == MAXU16 ? "%#x" : "%u", bpb->infs);
-	printf(" bkbs=");
-	printf(bpb->bkbs == MAXU16 ? "%#x" : "%u", bpb->bkbs);
+        printf(" bspf=%u rdcl=%u", bpb->bspf, bpb->rdcl);
+        printf(" infs=");
+        printf(bpb->infs == MAXU16 ? "%#x" : "%u", bpb->infs);
+        printf(" bkbs=");
+        printf(bpb->bkbs == MAXU16 ? "%#x" : "%u", bpb->bkbs);
     }
     printf("\n");
 }
@@ -927,21 +944,19 @@
 /*
  * Check a disk geometry value.
  */
-static u_int
-ckgeom(const char *fname, u_int val, const char *msg)
+static u_int ckgeom(const char *fname, u_int val, const char *msg)
 {
     if (!val)
-	errx(1, "%s: no default %s", fname, msg);
+        errx(1, "%s: no default %s", fname, msg);
     if (val > MAXU16)
-	errx(1, "%s: illegal %s %d", fname, msg, val);
+        errx(1, "%s: illegal %s %d", fname, msg, val);
     return val;
 }
 
 /*
  * Convert and check a numeric option argument.
  */
-static u_int
-argtou(const char *arg, u_int lo, u_int hi, const char *msg)
+static u_int argtou(const char *arg, u_int lo, u_int hi, const char *msg)
 {
     char *s;
     u_long x;
@@ -949,15 +964,14 @@
     errno = 0;
     x = strtoul(arg, &s, 0);
     if (errno || !*arg || *s || x < lo || x > hi)
-	errx(1, "%s: bad %s", arg, msg);
+        errx(1, "%s: bad %s", arg, msg);
     return x;
 }
 
 /*
  * Same for off_t, with optional skmgpP suffix
  */
-static off_t
-argtooff(const char *arg, const char *msg)
+static off_t argtooff(const char *arg, const char *msg)
 {
     char *s;
     off_t x;
@@ -965,40 +979,40 @@
     x = strtoll(arg, &s, 0);
     /* allow at most one extra char */
     if (errno || x < 0 || (s[0] && s[1]) )
-	errx(1, "%s: bad %s", arg, msg);
-    if (*s) {	/* the extra char is the multiplier */
-	switch (*s) {
-	default:
-	    errx(1, "%s: bad %s", arg, msg);
-	    /* notreached */
-	
-	case 's':	/* sector */
-	case 'S':
-	    x <<= 9;	/* times 512 */
-	    break;
+        errx(1, "%s: bad %s", arg, msg);
+    if (*s) {    /* the extra char is the multiplier */
+        switch (*s) {
+            default:
+                errx(1, "%s: bad %s", arg, msg);
+                /* notreached */
 
-	case 'k':	/* kilobyte */
-	case 'K':
-	    x <<= 10;	/* times 1024 */
-	    break;
+            case 's':       /* sector */
+            case 'S':
+                x <<= 9;    /* times 512 */
+                break;
 
-	case 'm':	/* megabyte */
-	case 'M':
-	    x <<= 20;	/* times 1024*1024 */
-	    break;
+            case 'k':       /* kilobyte */
+            case 'K':
+                x <<= 10;   /* times 1024 */
+                break;
 
-	case 'g':	/* gigabyte */
-	case 'G':
-	    x <<= 30;	/* times 1024*1024*1024 */
-	    break;
+            case 'm':       /* megabyte */
+            case 'M':
+                x <<= 20;   /* times 1024*1024 */
+                break;
 
-	case 'p':	/* partition start */
-	case 'P':	/* partition start */
-	case 'l':	/* partition length */
-	case 'L':	/* partition length */
-	    errx(1, "%s: not supported yet %s", arg, msg);
-	    /* notreached */
-	}
+            case 'g':       /* gigabyte */
+            case 'G':
+                x <<= 30;   /* times 1024*1024*1024 */
+                break;
+
+            case 'p':       /* partition start */
+            case 'P':       /* partition start */
+            case 'l':       /* partition length */
+            case 'L':       /* partition length */
+                errx(1, "%s: not supported yet %s", arg, msg);
+                /* notreached */
+        }
     }
     return x;
 }
@@ -1006,15 +1020,14 @@
 /*
  * Check a volume label.
  */
-static int
-oklabel(const char *src)
+static int oklabel(const char *src)
 {
     int c, i;
 
     for (i = 0; i <= 11; i++) {
-	c = (u_char)*src++;
-	if (c < ' ' + !i || strchr("\"*+,./:;<=>?[\\]|", c))
-	    break;
+        c = (u_char)*src++;
+        if (c < ' ' + !i || strchr("\"*+,./:;<=>?[\\]|", c))
+            break;
     }
     return i && !c;
 }
@@ -1022,58 +1035,56 @@
 /*
  * Make a volume label.
  */
-static void
-mklabel(u_int8_t *dest, const char *src)
+static void mklabel(u_int8_t *dest, const char *src)
 {
     int c, i;
 
     for (i = 0; i < 11; i++) {
-	c = *src ? toupper(*src++) : ' ';
-	*dest++ = !i && c == '\xe5' ? 5 : c;
+        c = *src ? toupper(*src++) : ' ';
+        *dest++ = !i && c == '\xe5' ? 5 : c;
     }
 }
 
 /*
  * Copy string, padding with spaces.
  */
-static void
-setstr(u_int8_t *dest, const char *src, size_t len)
+static void setstr(u_int8_t *dest, const char *src, size_t len)
 {
     while (len--)
-	*dest++ = *src ? *src++ : ' ';
+        *dest++ = *src ? *src++ : ' ';
 }
 
 /*
  * Print usage message.
  */
-static void
-usage(void)
+static void usage(void)
 {
-	fprintf(stderr,
-	    "usage: newfs_msdos [ -options ] special [disktype]\n"
-	    "where the options are:\n"
-	    "\t-@ create file system at specified offset\n"                         
-	    "\t-B get bootstrap from file\n"
-	    "\t-C create image file with specified size\n"
-	    "\t-F FAT type (12, 16, or 32)\n"
-	    "\t-I volume ID\n"
-	    "\t-L volume label\n"
-	    "\t-N don't create file system: just print out parameters\n"
-	    "\t-O OEM string\n"
-	    "\t-S bytes/sector\n"
-	    "\t-a sectors/FAT\n"
-	    "\t-b block size\n"
-	    "\t-c sectors/cluster\n"
-	    "\t-e root directory entries\n"
-	    "\t-f standard format\n"
-	    "\t-h drive heads\n"
-	    "\t-i file system info sector\n"
-	    "\t-k backup boot sector\n"
-	    "\t-m media descriptor\n"
-	    "\t-n number of FATs\n"
-	    "\t-o hidden sectors\n"
-	    "\t-r reserved sectors\n"
-	    "\t-s file system size (sectors)\n"
-	    "\t-u sectors/track\n");
-	exit(1);
+    fprintf(stderr,
+            "usage: newfs_msdos [ -options ] special [disktype]\n"
+            "where the options are:\n"
+            "\t-@ create file system at specified offset\n"
+            "\t-A Attempt to cluster align root directory\n"
+            "\t-B get bootstrap from file\n"
+            "\t-C create image file with specified size\n"
+            "\t-F FAT type (12, 16, or 32)\n"
+            "\t-I volume ID\n"
+            "\t-L volume label\n"
+            "\t-N don't create file system: just print out parameters\n"
+            "\t-O OEM string\n"
+            "\t-S bytes/sector\n"
+            "\t-a sectors/FAT\n"
+            "\t-b block size\n"
+            "\t-c sectors/cluster\n"
+            "\t-e root directory entries\n"
+            "\t-f standard format\n"
+            "\t-h drive heads\n"
+            "\t-i file system info sector\n"
+            "\t-k backup boot sector\n"
+            "\t-m media descriptor\n"
+            "\t-n number of FATs\n"
+            "\t-o hidden sectors\n"
+            "\t-r reserved sectors\n"
+            "\t-s file system size (sectors)\n"
+            "\t-u sectors/track\n");
+    exit(1);
 }
diff --git a/toolbox/printenv.c b/toolbox/printenv.c
deleted file mode 100644
index d5ea531..0000000
--- a/toolbox/printenv.c
+++ /dev/null
@@ -1,29 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-
-extern char** environ;
-
-int printenv_main (int argc, char **argv)
-{
-    char** e;
-    char* v;
-    int i;
-   
-    if (argc == 1) {
-        e = environ;
-        while (*e) {
-            printf("%s\n", *e);
-            e++;
-        }
-    } else {
-        for (i=1; i<argc; i++) {
-            v = getenv(argv[i]);
-            if (v) {
-                printf("%s\n", v);
-            }
-        }
-    }
-
-    return 0;
-}
-
diff --git a/toolbox/ps.c b/toolbox/ps.c
index 57b4280..5458f6b 100644
--- a/toolbox/ps.c
+++ b/toolbox/ps.c
@@ -28,7 +28,8 @@
 #define SHOW_POLICY 4
 #define SHOW_CPU  8
 #define SHOW_MACLABEL 16
-#define SHOW_ABI 32
+#define SHOW_NUMERIC_UID 32
+#define SHOW_ABI 64
 
 static int display_flags = 0;
 
@@ -48,7 +49,7 @@
     unsigned utime, stime;
     int prio, nice, rtprio, sched, psr;
     struct passwd *pw;
-    
+
     sprintf(statline, "/proc/%d", pid);
     stat(statline, &stats);
 
@@ -70,7 +71,7 @@
         }
         cmdline[r] = 0;
     }
-    
+
     fd = open(statline, O_RDONLY);
     if(fd == 0) return -1;
     r = read(fd, statline, 1023);
@@ -92,7 +93,6 @@
     nexttok(&ptr); // pgrp
     nexttok(&ptr); // sid
     nexttok(&ptr); // tty
-    
     nexttok(&ptr); // tpgid
     nexttok(&ptr); // flags
     nexttok(&ptr); // minflt
@@ -132,21 +132,21 @@
     psr = atoi(nexttok(&ptr)); // processor
     rtprio = atoi(nexttok(&ptr)); // rt_priority
     sched = atoi(nexttok(&ptr)); // scheduling policy
-    
+
     nexttok(&ptr); // tty
-    
+
     if(tid != 0) {
         ppid = pid;
         pid = tid;
     }
 
     pw = getpwuid(stats.st_uid);
-    if(pw == 0) {
+    if(pw == 0 || (display_flags & SHOW_NUMERIC_UID)) {
         sprintf(user,"%d",(int)stats.st_uid);
     } else {
         strcpy(user,pw->pw_name);
     }
-    
+
     if(!namefilter || !strncmp(name, namefilter, strlen(namefilter))) {
         if (display_flags & SHOW_MACLABEL) {
             fd = open(macline, O_RDONLY);
@@ -229,7 +229,7 @@
     sprintf(tmp,"/proc/%d/task",pid);
     d = opendir(tmp);
     if(d == 0) return;
-    
+
     while((de = readdir(d)) != 0){
         if(isdigit(de->d_name[0])){
             int tid = atoi(de->d_name);
@@ -237,7 +237,7 @@
             ps_line(pid, tid, namefilter);
         }
     }
-    closedir(d);    
+    closedir(d);
 }
 
 int ps_main(int argc, char **argv)
@@ -247,13 +247,15 @@
     char *namefilter = 0;
     int pidfilter = 0;
     int threads = 0;
-    
+
     d = opendir("/proc");
     if(d == 0) return -1;
 
     while(argc > 1){
         if(!strcmp(argv[1],"-t")) {
             threads = 1;
+        } else if(!strcmp(argv[1],"-n")) {
+            display_flags |= SHOW_NUMERIC_UID;
         } else if(!strcmp(argv[1],"-x")) {
             display_flags |= SHOW_TIME;
         } else if(!strcmp(argv[1], "-Z")) {
diff --git a/toolbox/uid_from_user.c b/toolbox/pwcache.c
similarity index 75%
rename from toolbox/uid_from_user.c
rename to toolbox/pwcache.c
index fd48d3c..9d81981 100644
--- a/toolbox/uid_from_user.c
+++ b/toolbox/pwcache.c
@@ -26,7 +26,9 @@
  * SUCH DAMAGE.
  */
 
+#include <grp.h>
 #include <pwd.h>
+#include <stdio.h>
 #include <sys/types.h>
 
 int uid_from_user(const char* name, uid_t* uid) {
@@ -37,3 +39,23 @@
   *uid = pw->pw_uid;
   return 0;
 }
+
+char* group_from_gid(gid_t gid, int noname) {
+  struct group* g = getgrgid(gid);
+  if (g == NULL) {
+    static char buf[32];
+    snprintf(buf, sizeof(buf), "%lu", (long) gid);
+    return noname ? NULL : buf;
+  }
+  return g->gr_name;
+}
+
+char* user_from_uid(uid_t uid, int noname) {
+  struct passwd* pw = getpwuid(uid);
+  if (pw == NULL) {
+    static char buf[32];
+    snprintf(buf, sizeof(buf), "%lu", (long) uid);
+    return noname ? NULL : buf;
+  }
+  return pw->pw_name;
+}
diff --git a/toolbox/rm.c b/toolbox/rm.c
deleted file mode 100644
index 957b586..0000000
--- a/toolbox/rm.c
+++ /dev/null
@@ -1,126 +0,0 @@
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <dirent.h>
-#include <limits.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#define OPT_RECURSIVE 1
-#define OPT_FORCE     2
-
-static int usage()
-{
-    fprintf(stderr,"Usage: rm [-rR] [-f] <target>\n");
-    return -1;
-}
-
-/* return -1 on failure, with errno set to the first error */
-static int unlink_recursive(const char* name, int flags)
-{
-    struct stat st;
-    DIR *dir;
-    struct dirent *de;
-    int fail = 0;
-
-    /* is it a file or directory? */
-    if (lstat(name, &st) < 0)
-        return ((flags & OPT_FORCE) && errno == ENOENT) ? 0 : -1;
-
-    /* a file, so unlink it */
-    if (!S_ISDIR(st.st_mode))
-        return unlink(name);
-
-    /* a directory, so open handle */
-    dir = opendir(name);
-    if (dir == NULL)
-        return -1;
-
-    /* recurse over components */
-    errno = 0;
-    while ((de = readdir(dir)) != NULL) {
-        char dn[PATH_MAX];
-        if (!strcmp(de->d_name, "..") || !strcmp(de->d_name, "."))
-            continue;
-        sprintf(dn, "%s/%s", name, de->d_name);
-        if (unlink_recursive(dn, flags) < 0) {
-            if (!(flags & OPT_FORCE)) {
-                fail = 1;
-                break;
-            }
-        }
-        errno = 0;
-    }
-    /* in case readdir or unlink_recursive failed */
-    if (fail || errno < 0) {
-        int save = errno;
-        closedir(dir);
-        errno = save;
-        return -1;
-    }
-
-    /* close directory handle */
-    if (closedir(dir) < 0)
-        return -1;
-
-    /* delete target directory */
-    return rmdir(name);
-}
-
-int rm_main(int argc, char *argv[])
-{
-    int ret;
-    int i, c;
-    int flags = 0;
-    int something_failed = 0;
-
-    if (argc < 2)
-        return usage();
-
-    /* check flags */
-    do {
-        c = getopt(argc, argv, "frR");
-        if (c == EOF)
-            break;
-        switch (c) {
-        case 'f':
-            flags |= OPT_FORCE;
-            break;
-        case 'r':
-        case 'R':
-            flags |= OPT_RECURSIVE;
-            break;
-        }
-    } while (1);
-
-    if (optind < 1 || optind >= argc) {
-        usage();
-        return -1;
-    }
-
-    /* loop over the file/directory args */
-    for (i = optind; i < argc; i++) {
-
-        if (flags & OPT_RECURSIVE) {
-            ret = unlink_recursive(argv[i], flags);
-        } else {
-            ret = unlink(argv[i]);
-            if (ret < 0 && errno == ENOENT && (flags & OPT_FORCE)) {
-                continue;
-            }
-        }
-
-        if (ret < 0) {
-            fprintf(stderr, "rm failed for %s, %s\n", argv[i], strerror(errno));
-            if (!(flags & OPT_FORCE)) {
-                return -1;
-            } else {
-                something_failed = 1;
-            }
-        }
-    }
-
-    return something_failed;
-}
-
diff --git a/toolbox/rmdir.c b/toolbox/rmdir.c
deleted file mode 100644
index 749fec8..0000000
--- a/toolbox/rmdir.c
+++ /dev/null
@@ -1,28 +0,0 @@
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-
-static int usage()
-{
-    fprintf(stderr,"rmdir <directory>\n");
-    return -1;
-}
-
-int rmdir_main(int argc, char *argv[])
-{
-    int ret;
-    if(argc < 2) return usage();
-
-    while(argc > 1) {
-        argc--;
-        argv++;
-        ret = rmdir(argv[0]);
-        if(ret < 0) {
-            fprintf(stderr, "rmdir failed for %s, %s\n", argv[0], strerror(errno));
-            return ret;
-        }
-    }
-    
-    return 0;
-}
diff --git a/toolbox/sleep.c b/toolbox/sleep.c
deleted file mode 100644
index c09ae03..0000000
--- a/toolbox/sleep.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 2008, The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the 
- *    distribution.
- *  * Neither the name of Google, Inc. nor the names of its contributors
- *    may be used to endorse or promote products derived from this
- *    software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-
-static void
-usage(const char *s)
-{
-    fprintf(stderr, "USAGE: %s SECONDS\n", s);
-    exit(-1);
-}
-
-int sleep_main(int argc, char *argv[])
-{
-    unsigned long seconds;
-    char *endptr;
-
-    if (argc != 2) {
-        usage(argv[0]);
-    }
-
-    seconds = strtoul(argv[1], &endptr, 10);
-
-    if (endptr == argv[1]) {
-        usage(argv[0]);
-    }
-
-
-    sleep((unsigned int)seconds);
-   
-    return 0;
-}
-
-
diff --git a/toolbox/start.c b/toolbox/start.c
index 0941e64..6c8a3f2 100644
--- a/toolbox/start.c
+++ b/toolbox/start.c
@@ -11,6 +11,7 @@
         property_set("ctl.start", argv[1]);
     } else {
         /* defaults to starting the common services stopped by stop.c */
+        property_set("ctl.start", "netd");
         property_set("ctl.start", "surfaceflinger");
         property_set("ctl.start", "zygote");
         property_set("ctl.start", "zygote_secondary");
diff --git a/toolbox/stop.c b/toolbox/stop.c
index ed9a293..5e3ce3c 100644
--- a/toolbox/stop.c
+++ b/toolbox/stop.c
@@ -12,6 +12,7 @@
         property_set("ctl.stop", "zygote_secondary");
         property_set("ctl.stop", "zygote");
         property_set("ctl.stop", "surfaceflinger");
+        property_set("ctl.stop", "netd");
     }
 
     return 0;
diff --git a/toolbox/swapon.c b/toolbox/swapon.c
index 21d2287..150701a 100644
--- a/toolbox/swapon.c
+++ b/toolbox/swapon.c
@@ -4,13 +4,13 @@
 #include <getopt.h>
 #include <sys/swap.h>
 
-void usage(char *name)
+static void usage(char *name)
 {
     fprintf(stderr, "Usage: %s [-p prio] <filename>\n"
         "        prio must be between 0 and %d\n", name, SWAP_FLAG_PRIO_MASK);
 }
 
-int parse_prio(char *prio_str)
+static int parse_prio(char *prio_str)
 {
     unsigned long p = strtoul(prio_str, NULL, 10);
 
diff --git a/toolbox/sync.c b/toolbox/sync.c
deleted file mode 100644
index 8284276..0000000
--- a/toolbox/sync.c
+++ /dev/null
@@ -1,7 +0,0 @@
-#include <unistd.h>
-
-int sync_main(int argc, char **argv)
-{
-	sync();
-	return 0;
-}
diff --git a/toolbox/cat.c b/toolbox/upstream-netbsd/bin/cat/cat.c
similarity index 67%
rename from toolbox/cat.c
rename to toolbox/upstream-netbsd/bin/cat/cat.c
index 6ac31f8..cca8cf5 100644
--- a/toolbox/cat.c
+++ b/toolbox/upstream-netbsd/bin/cat/cat.c
@@ -1,4 +1,4 @@
-/* $NetBSD: cat.c,v 1.43 2004/01/04 03:31:28 jschauma Exp $	*/
+/* $NetBSD: cat.c,v 1.54 2013/12/08 08:32:13 spz Exp $	*/
 
 /*
  * Copyright (c) 1989, 1993
@@ -32,208 +32,59 @@
  * SUCH DAMAGE.
  */
 
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
+#include <sys/cdefs.h>
+#if !defined(lint)
+__COPYRIGHT(
+"@(#) Copyright (c) 1989, 1993\
+ The Regents of the University of California.  All rights reserved.");
+#if 0
+static char sccsid[] = "@(#)cat.c	8.2 (Berkeley) 4/27/95";
+#else
+__RCSID("$NetBSD: cat.c,v 1.54 2013/12/08 08:32:13 spz Exp $");
+#endif
+#endif /* not lint */
+
 #include <sys/param.h>
 #include <sys/stat.h>
 
 #include <ctype.h>
+#include <err.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <locale.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
-#define CAT_BUFSIZ (4096)
-
 static int bflag, eflag, fflag, lflag, nflag, sflag, tflag, vflag;
+static size_t bsize;
 static int rval;
 static const char *filename;
 
-static void
-cook_buf(FILE *fp)
-{
-	int ch, gobble, line, prev;
-	int stdout_err = 0;
-
-	line = gobble = 0;
-	for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) {
-		if (prev == '\n') {
-			if (ch == '\n') {
-				if (sflag) {
-					if (!gobble && putchar(ch) == EOF)
-						break;
-					gobble = 1;
-					continue;
-				}
-				if (nflag) {
-					if (!bflag) {
-						if (fprintf(stdout,
-						    "%6d\t", ++line) < 0) {
-							stdout_err++;
-							break;
-						}
-					} else if (eflag) {
-						if (fprintf(stdout,
-						    "%6s\t", "") < 0) {
-							stdout_err++;
-							break;
-						}
-					}
-				}
-			} else if (nflag) {
-				if (fprintf(stdout, "%6d\t", ++line) < 0) {
-					stdout_err++;
-					break;
-				}
-			}
-		}
-		gobble = 0;
-		if (ch == '\n') {
-			if (eflag)
-				if (putchar('$') == EOF)
-					break;
-		} else if (ch == '\t') {
-			if (tflag) {
-				if (putchar('^') == EOF || putchar('I') == EOF)
-					break;
-				continue;
-			}
-		} else if (vflag) {
-			if (!isascii(ch)) {
-				if (putchar('M') == EOF || putchar('-') == EOF)
-					break;
-				ch = (ch) & 0x7f;
-			}
-			if (iscntrl(ch)) {
-				if (putchar('^') == EOF ||
-				    putchar(ch == '\177' ? '?' :
-				    ch | 0100) == EOF)
-					break;
-				continue;
-			}
-		}
-		if (putchar(ch) == EOF)
-			break;
-	}
-	if (stdout_err) {
-		perror(filename);
-		rval = 1;
-	}
-}
-
-static void
-cook_args(char **argv)
-{
-	FILE *fp;
-
-	fp = stdin;
-	filename = "stdin";
-	do {
-		if (*argv) {
-			if (!strcmp(*argv, "-"))
-				fp = stdin;
-			else if ((fp = fopen(*argv,
-			    fflag ? "rf" : "r")) == NULL) {
-				perror("fopen");
-				rval = 1;
-				++argv;
-				continue;
-			}
-			filename = *argv++;
-		}
-		cook_buf(fp);
-		if (fp != stdin)
-			fclose(fp);
-	} while (*argv);
-}
-
-static void
-raw_cat(int rfd)
-{
-	static char *buf;
-	static char fb_buf[CAT_BUFSIZ];
-	static size_t bsize;
-
-	struct stat sbuf;
-	ssize_t nr, nw, off;
-	int wfd;
-
-	wfd = fileno(stdout);
-	if (buf == NULL) {
-		if (fstat(wfd, &sbuf) == 0) {
-			bsize = sbuf.st_blksize > CAT_BUFSIZ ?
-			    sbuf.st_blksize : CAT_BUFSIZ;
-			buf = malloc(bsize);
-		}
-		if (buf == NULL) {
-			buf = fb_buf;
-			bsize = CAT_BUFSIZ;
-		}
-	}
-	while ((nr = read(rfd, buf, bsize)) > 0)
-		for (off = 0; nr; nr -= nw, off += nw)
-			if ((nw = write(wfd, buf + off, (size_t)nr)) < 0)
-			{
-				perror("write");
-				exit(EXIT_FAILURE);
-			}
-	if (nr < 0) {
-		fprintf(stderr,"%s: invalid length\n", filename);
-		rval = 1;
-	}
-}
-
-static void
-raw_args(char **argv)
-{
-	int fd;
-
-	fd = fileno(stdin);
-	filename = "stdin";
-	do {
-		if (*argv) {
-			if (!strcmp(*argv, "-"))
-				fd = fileno(stdin);
-			else if (fflag) {
-				struct stat st;
-				fd = open(*argv, O_RDONLY|O_NONBLOCK, 0);
-				if (fd < 0)
-					goto skip;
-
-				if (fstat(fd, &st) == -1) {
-					close(fd);
-					goto skip;
-				}
-				if (!S_ISREG(st.st_mode)) {
-					close(fd);
-					errno = EINVAL;
-					goto skipnomsg;
-				}
-			}
-			else if ((fd = open(*argv, O_RDONLY, 0)) < 0) {
-skip:
-				perror(*argv);
-skipnomsg:
-				rval = 1;
-				++argv;
-				continue;
-			}
-			filename = *argv++;
-		}
-		raw_cat(fd);
-		if (fd != fileno(stdin))
-			close(fd);
-	} while (*argv);
-}
+void cook_args(char *argv[]);
+void cook_buf(FILE *);
+void raw_args(char *argv[]);
+void raw_cat(int);
 
 int
-cat_main(int argc, char *argv[])
+main(int argc, char *argv[])
 {
 	int ch;
 	struct flock stdout_lock;
 
-	while ((ch = getopt(argc, argv, "beflnstv")) != -1)
+	setprogname(argv[0]);
+	(void)setlocale(LC_ALL, "");
+
+	while ((ch = getopt(argc, argv, "B:beflnstuv")) != -1)
 		switch (ch) {
+		case 'B':
+			bsize = (size_t)strtol(optarg, NULL, 0);
+			break;
 		case 'b':
 			bflag = nflag = 1;	/* -b implies -n */
 			break;
@@ -255,14 +106,18 @@
 		case 't':
 			tflag = vflag = 1;	/* -t implies -v */
 			break;
+		case 'u':
+			setbuf(stdout, NULL);
+			break;
 		case 'v':
 			vflag = 1;
 			break;
 		default:
 		case '?':
-			fprintf(stderr,
-				"usage: cat [-beflnstv] [-] [file ...]\n");
-			exit(EXIT_FAILURE);
+			(void)fprintf(stderr,
+			    "Usage: %s [-beflnstuv] [-B bsize] [-] "
+			    "[file ...]\n", getprogname());
+			return EXIT_FAILURE;
 		}
 	argv += optind;
 
@@ -272,10 +127,7 @@
 		stdout_lock.l_type = F_WRLCK;
 		stdout_lock.l_whence = SEEK_SET;
 		if (fcntl(STDOUT_FILENO, F_SETLKW, &stdout_lock) == -1)
-		{
-			perror("fcntl");
-			exit(EXIT_FAILURE);
-		}
+			err(EXIT_FAILURE, "stdout");
 	}
 
 	if (bflag || eflag || nflag || sflag || tflag || vflag)
@@ -283,9 +135,195 @@
 	else
 		raw_args(argv);
 	if (fclose(stdout))
-	{
-		perror("fclose");
-		exit(EXIT_FAILURE);
+		err(EXIT_FAILURE, "stdout");
+	return rval;
+}
+
+void
+cook_args(char **argv)
+{
+	FILE *fp;
+
+	fp = stdin;
+	filename = "stdin";
+	do {
+		if (*argv) {
+			if (!strcmp(*argv, "-"))
+				fp = stdin;
+			else if ((fp = fopen(*argv,
+			    fflag ? "rf" : "r")) == NULL) {
+				warn("%s", *argv);
+				rval = EXIT_FAILURE;
+				++argv;
+				continue;
+			}
+			filename = *argv++;
+		}
+		cook_buf(fp);
+		if (fp != stdin)
+			(void)fclose(fp);
+		else
+			clearerr(fp);
+	} while (*argv);
+}
+
+void
+cook_buf(FILE *fp)
+{
+	int ch, gobble, line, prev;
+
+	line = gobble = 0;
+	for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) {
+		if (prev == '\n') {
+			if (ch == '\n') {
+				if (sflag) {
+					if (!gobble && nflag && !bflag)
+						(void)fprintf(stdout,
+							"%6d\t\n", ++line);
+					else if (!gobble && putchar(ch) == EOF)
+						break;
+					gobble = 1;
+					continue;
+				}
+				if (nflag) {
+					if (!bflag) {
+						(void)fprintf(stdout,
+						    "%6d\t", ++line);
+						if (ferror(stdout))
+							break;
+					} else if (eflag) {
+						(void)fprintf(stdout,
+						    "%6s\t", "");
+						if (ferror(stdout))
+							break;
+					}
+				}
+			} else if (nflag) {
+				(void)fprintf(stdout, "%6d\t", ++line);
+				if (ferror(stdout))
+					break;
+			}
+		}
+		gobble = 0;
+		if (ch == '\n') {
+			if (eflag)
+				if (putchar('$') == EOF)
+					break;
+		} else if (ch == '\t') {
+			if (tflag) {
+				if (putchar('^') == EOF || putchar('I') == EOF)
+					break;
+				continue;
+			}
+		} else if (vflag) {
+			if (!isascii(ch)) {
+				if (putchar('M') == EOF || putchar('-') == EOF)
+					break;
+				ch = toascii(ch);
+			}
+			if (iscntrl(ch)) {
+				if (putchar('^') == EOF ||
+				    putchar(ch == '\177' ? '?' :
+				    ch | 0100) == EOF)
+					break;
+				continue;
+			}
+		}
+		if (putchar(ch) == EOF)
+			break;
 	}
-	exit(rval);
+	if (ferror(fp)) {
+		warn("%s", filename);
+		rval = EXIT_FAILURE;
+		clearerr(fp);
+	}
+	if (ferror(stdout))
+		err(EXIT_FAILURE, "stdout");
+}
+
+void
+raw_args(char **argv)
+{
+	int fd;
+
+	fd = fileno(stdin);
+	filename = "stdin";
+	do {
+		if (*argv) {
+			if (!strcmp(*argv, "-")) {
+				fd = fileno(stdin);
+				if (fd < 0)
+					goto skip;
+			} else if (fflag) {
+				struct stat st;
+				fd = open(*argv, O_RDONLY|O_NONBLOCK, 0);
+				if (fd < 0)
+					goto skip;
+
+				if (fstat(fd, &st) == -1) {
+					close(fd);
+					goto skip;
+				}
+				if (!S_ISREG(st.st_mode)) {
+					close(fd);
+					warnx("%s: not a regular file", *argv);
+					goto skipnomsg;
+				}
+			}
+			else if ((fd = open(*argv, O_RDONLY, 0)) < 0) {
+skip:
+				warn("%s", *argv);
+skipnomsg:
+				rval = EXIT_FAILURE;
+				++argv;
+				continue;
+			}
+			filename = *argv++;
+		} else if (fd < 0) {
+			err(EXIT_FAILURE, "stdin");
+		}
+		raw_cat(fd);
+		if (fd != fileno(stdin))
+			(void)close(fd);
+	} while (*argv);
+}
+
+void
+raw_cat(int rfd)
+{
+	static char *buf;
+	static char fb_buf[BUFSIZ];
+
+	ssize_t nr, nw, off;
+	int wfd;
+
+	wfd = fileno(stdout);
+	if (wfd < 0)
+		err(EXIT_FAILURE, "stdout");
+	if (buf == NULL) {
+		struct stat sbuf;
+
+		if (bsize == 0) {
+			if (fstat(wfd, &sbuf) == 0 && sbuf.st_blksize > 0 &&
+			    (size_t)sbuf.st_blksize > sizeof(fb_buf))
+				bsize = sbuf.st_blksize;
+		}
+		if (bsize > sizeof(fb_buf)) {
+			buf = malloc(bsize);
+			if (buf == NULL)
+				warnx("malloc, using %zu buffer", bsize);
+		}
+		if (buf == NULL) {
+			bsize = sizeof(fb_buf);
+			buf = fb_buf;
+		}
+	}
+	while ((nr = read(rfd, buf, bsize)) > 0)
+		for (off = 0; nr; nr -= nw, off += nw)
+			if ((nw = write(wfd, buf + off, (size_t)nr)) < 0)
+				err(EXIT_FAILURE, "stdout");
+	if (nr < 0) {
+		warn("%s", filename);
+		rval = EXIT_FAILURE;
+	}
 }
diff --git a/toolbox/cp/cp.c b/toolbox/upstream-netbsd/bin/cp/cp.c
similarity index 95%
rename from toolbox/cp/cp.c
rename to toolbox/upstream-netbsd/bin/cp/cp.c
index e666453..4bbe1b7 100644
--- a/toolbox/cp/cp.c
+++ b/toolbox/upstream-netbsd/bin/cp/cp.c
@@ -49,11 +49,11 @@
 
 /*
  * Cp copies source files to target files.
- *
+ * 
  * The global PATH_T structure "to" always contains the path to the
  * current target file.  Since fts(3) does not change directories,
  * this path can be either absolute or dot-relative.
- *
+ * 
  * The basic algorithm is to initialize "to" and use fts(3) to traverse
  * the file hierarchy rooted in the argument list.  A trivial case is the
  * case of 'cp file1 file2'.  The more interesting case is the case of
@@ -95,30 +95,26 @@
 
 static int copy(char *[], enum op, int);
 
-#ifndef ANDROID
 static void
 progress(int sig __unused)
 {
 
 	pinfo++;
 }
-#endif
 
 int
-cp_main(int argc, char *argv[])
+main(int argc, char *argv[])
 {
 	struct stat to_stat, tmp_stat;
 	enum op type;
 	int ch, fts_options, r, have_trailing_slash;
 	char *target, **src;
 
-#ifndef ANDROID
 	setprogname(argv[0]);
-#endif
 	(void)setlocale(LC_ALL, "");
 
 	Hflag = Lflag = Pflag = Rflag = 0;
-	while ((ch = getopt(argc, argv, "HLNPRfailprv")) != -1)
+	while ((ch = getopt(argc, argv, "HLNPRfailprv")) != -1) 
 		switch (ch) {
 		case 'H':
 			Hflag = 1;
@@ -166,14 +162,14 @@
 			break;
 		case '?':
 		default:
-			cp_usage();
+			usage();
 			/* NOTREACHED */
 		}
 	argc -= optind;
 	argv += optind;
 
 	if (argc < 2)
-		cp_usage();
+		usage();
 
 	fts_options = FTS_NOCHDIR | FTS_PHYSICAL;
 	if (rflag) {
@@ -220,12 +216,10 @@
 	to.target_end = to.p_end;
 
 	/* Set end of argument list for fts(3). */
-	argv[argc] = NULL;
-
-#ifndef ANDROID
+	argv[argc] = NULL;     
+	
 	(void)signal(SIGINFO, progress);
-#endif
-
+	
 	/*
 	 * Cp has two distinct cases:
 	 *
@@ -251,9 +245,9 @@
 	if (r == -1 || !S_ISDIR(to_stat.st_mode)) {
 		/*
 		 * Case (1).  Target is not a directory.
-		 */
+		 */ 
 		if (argc > 1)
-			cp_usage();
+			usage();
 		/*
 		 * Need to detect the case:
 		 *	cp -R dir foo
@@ -270,7 +264,7 @@
 				err(EXIT_FAILURE, "%s", *argv);
 				/* NOTREACHED */
 			}
-
+			
 			if (S_ISDIR(tmp_stat.st_mode) && (Rflag || rflag))
 				type = DIR_TO_DNE;
 			else
@@ -359,8 +353,8 @@
 		}
 
 		/*
-		 * If we are in case (2) or (3) above, we need to append the
-                 * source name to the target name.
+		 * If we are in case (2) or (3) above, we need to append the 
+                 * source name to the target name.  
                  */
 		if (type != FILE_TO_FILE) {
 			if ((curr->fts_namelen +
@@ -393,10 +387,10 @@
 			if (curr->fts_level == FTS_ROOTLEVEL) {
 				if (type != DIR_TO_DNE) {
 					p = strrchr(curr->fts_path, '/');
-					base = (p == NULL) ? 0 :
+					base = (p == NULL) ? 0 : 
 					    (int)(p - curr->fts_path + 1);
 
-					if (!strcmp(&curr->fts_path[base],
+					if (!strcmp(&curr->fts_path[base], 
 					    ".."))
 						base += 1;
 				} else
@@ -453,7 +447,7 @@
 			   ((fts_options & FTS_COMFOLLOW) && curr->fts_level == 0)) {
 				if (copy_file(curr, dne))
 					this_failed = any_failed = 1;
-			} else {
+			} else {	
 				if (copy_link(curr, !dne))
 					this_failed = any_failed = 1;
 			}
@@ -485,7 +479,7 @@
 				 */
 				pushdne(dne);
 				if (dne) {
-					if (mkdir(to.p_path,
+					if (mkdir(to.p_path, 
 					    curr->fts_statp->st_mode | S_IRWXU) < 0)
 						err(EXIT_FAILURE, "%s",
 						    to.p_path);
@@ -501,14 +495,14 @@
 			{
 	                        /*
 				 * If not -p and directory didn't exist, set it to be
-				 * the same as the from directory, umodified by the
-				 * umask; arguably wrong, but it's been that way
-				 * forever.
+				 * the same as the from directory, umodified by the 
+                        	 * umask; arguably wrong, but it's been that way 
+                        	 * forever.
 				 */
 				if (pflag && setfile(curr->fts_statp, 0))
 					this_failed = any_failed = 1;
 				else if ((dne = popdne()))
-					(void)chmod(to.p_path,
+					(void)chmod(to.p_path, 
 					    curr->fts_statp->st_mode);
 			}
 			else
@@ -533,7 +527,7 @@
 			if (Rflag) {
 				if (copy_fifo(curr->fts_statp, !dne))
 					this_failed = any_failed = 1;
-			} else
+			} else 
 				if (copy_file(curr, dne))
 					this_failed = any_failed = 1;
 			break;
diff --git a/toolbox/cp/extern.h b/toolbox/upstream-netbsd/bin/cp/extern.h
similarity index 97%
rename from toolbox/cp/extern.h
rename to toolbox/upstream-netbsd/bin/cp/extern.h
index ffbadf7..e393844 100644
--- a/toolbox/cp/extern.h
+++ b/toolbox/upstream-netbsd/bin/cp/extern.h
@@ -55,7 +55,7 @@
 int	copy_special(struct stat *, int);
 int	set_utimes(const char *, struct stat *);
 int	setfile(struct stat *, int);
-void cp_usage(void) __attribute__((__noreturn__));
+void	usage(void) __attribute__((__noreturn__));
 __END_DECLS
 
 #endif /* !_EXTERN_H_ */
diff --git a/toolbox/cp/utils.c b/toolbox/upstream-netbsd/bin/cp/utils.c
similarity index 92%
rename from toolbox/cp/utils.c
rename to toolbox/upstream-netbsd/bin/cp/utils.c
index 9d0390f..d8f900a 100644
--- a/toolbox/cp/utils.c
+++ b/toolbox/upstream-netbsd/bin/cp/utils.c
@@ -1,4 +1,4 @@
-/* $NetBSD: utils.c,v 1.41 2012/01/04 15:58:37 christos Exp $ */
+/* $NetBSD: utils.c,v 1.42 2013/12/11 06:00:11 dholland Exp $ */
 
 /*-
  * Copyright (c) 1991, 1993, 1994
@@ -34,7 +34,7 @@
 #if 0
 static char sccsid[] = "@(#)utils.c	8.3 (Berkeley) 4/1/94";
 #else
-__RCSID("$NetBSD: utils.c,v 1.41 2012/01/04 15:58:37 christos Exp $");
+__RCSID("$NetBSD: utils.c,v 1.42 2013/12/11 06:00:11 dholland Exp $");
 #endif
 #endif /* not lint */
 
@@ -42,9 +42,7 @@
 #include <sys/param.h>
 #include <sys/stat.h>
 #include <sys/time.h>
-#ifndef ANDROID
 #include <sys/extattr.h>
-#endif
 
 #include <err.h>
 #include <errno.h>
@@ -58,10 +56,6 @@
 
 #include "extern.h"
 
-#ifdef ANDROID
-#define MAXBSIZE 65536
-#endif
-
 #define	MMAP_MAX_SIZE	(8 * 1048576)
 #define	MMAP_MAX_WRITE	(64 * 1024)
 
@@ -70,7 +64,7 @@
 {
     static struct timeval tv[2];
 
-#ifdef ANDROID
+#ifdef __ANDROID__
     tv[0].tv_sec = fs->st_atime;
     tv[0].tv_usec = 0;
     tv[1].tv_sec = fs->st_mtime;
@@ -85,8 +79,8 @@
     TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtimespec);
 
     if (lutimes(file, tv)) {
-    warn("lutimes: %s", file);
-    return (1);
+	warn("lutimes: %s", file);
+	return (1);
     }
 #endif
     return (0);
@@ -116,7 +110,7 @@
 	int ch, checkch, from_fd, rcount, rval, to_fd, tolnk, wcount;
 	char *p;
 	size_t ptotal = 0;
-
+	
 	if ((from_fd = open(entp->fts_path, O_RDONLY, 0)) == -1) {
 		warn("%s", entp->fts_path);
 		return (1);
@@ -192,13 +186,14 @@
 		}
 		return (0);
 	}
-	/* NOTREACHED */
 
 	/*
 	 * There's no reason to do anything other than close the file
 	 * now if it's empty, so let's not bother.
 	 */
+#ifndef __ANDROID__ // Files in /proc report length 0. mmap will fail but we'll fall back to read.
 	if (fs->st_size > 0) {
+#endif
 		struct finfo fi;
 
 		fi.from = entp->fts_path;
@@ -273,9 +268,11 @@
 				rval = 1;
 			}
 		}
+#ifndef __ANDROID__
 	}
+#endif
 
-#ifndef ANDROID
+#ifndef __ANDROID__
 	if (pflag && (fcpxattr(from_fd, to_fd) != 0))
 		warn("%s: error copying extended attributes", to.p_path);
 #endif
@@ -311,7 +308,7 @@
 		rval = 1;
 	}
 	/* set the mod/access times now after close of the fd */
-	if (pflag && set_utimes(to.p_path, fs)) {
+	if (pflag && set_utimes(to.p_path, fs)) { 
 	    rval = 1;
 	}
 	return (rval);
@@ -380,11 +377,10 @@
 int
 setfile(struct stat *fs, int fd)
 {
-	int rval = 0;
-#ifndef ANDROID
-	int islink = S_ISLNK(fs->st_mode);
-#endif
+	int rval, islink;
 
+	rval = 0;
+	islink = S_ISLNK(fs->st_mode);
 	fs->st_mode &= S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO;
 
 	/*
@@ -401,16 +397,16 @@
 		}
 		fs->st_mode &= ~(S_ISUID | S_ISGID);
 	}
-#ifdef ANDROID
-        if (fd ? fchmod(fd, fs->st_mode) : chmod(to.p_path, fs->st_mode)) {
+#ifdef __ANDROID__
+	if (fd ? fchmod(fd, fs->st_mode) : chmod(to.p_path, fs->st_mode)) {
 #else
-        if (fd ? fchmod(fd, fs->st_mode) : lchmod(to.p_path, fs->st_mode)) {
+	if (fd ? fchmod(fd, fs->st_mode) : lchmod(to.p_path, fs->st_mode)) {
 #endif
-                warn("chmod: %s", to.p_path);
-                rval = 1;
-        }
+		warn("chmod: %s", to.p_path);
+		rval = 1;
+	}
 
-#ifndef ANDROID
+#ifndef __ANDROID__
 	if (!islink && !Nflag) {
 		unsigned long fflags = fs->st_flags;
 		/*
@@ -437,11 +433,12 @@
 }
 
 void
-cp_usage(void)
+usage(void)
 {
 	(void)fprintf(stderr,
-	    "usage: cp [-R [-H | -L | -P]] [-f | -i] [-alNpv] src target\n"
-	    "       cp [-R [-H | -L | -P]] [-f | -i] [-alNpv] src1 ... srcN directory\n");
+	    "usage: %s [-R [-H | -L | -P]] [-f | -i] [-alNpv] src target\n"
+	    "       %s [-R [-H | -L | -P]] [-f | -i] [-alNpv] src1 ... srcN directory\n",
+	    getprogname(), getprogname());
 	exit(1);
 	/* NOTREACHED */
 }
diff --git a/toolbox/upstream-netbsd/bin/dd/args.c b/toolbox/upstream-netbsd/bin/dd/args.c
new file mode 100644
index 0000000..207e300
--- /dev/null
+++ b/toolbox/upstream-netbsd/bin/dd/args.c
@@ -0,0 +1,391 @@
+/*	$NetBSD: args.c,v 1.38 2013/07/17 12:55:48 christos Exp $	*/
+
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego and Lance
+ * Visser of Convex Computer Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)args.c	8.3 (Berkeley) 4/2/94";
+#else
+__RCSID("$NetBSD: args.c,v 1.38 2013/07/17 12:55:48 christos Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "dd.h"
+#include "extern.h"
+
+static int	c_arg(const void *, const void *);
+
+#ifdef NO_MSGFMT
+static void	f_msgfmt(char *) __dead;
+#else
+static void	f_msgfmt(char *);
+#endif /* NO_MSGFMT */
+
+#ifdef NO_CONV
+static void	f_conv(char *) __dead;
+#else
+static void	f_conv(char *);
+static int	c_conv(const void *, const void *);
+#endif /* NO_CONV */
+
+static void	f_bs(char *);
+static void	f_cbs(char *);
+static void	f_count(char *);
+static void	f_files(char *);
+static void	f_ibs(char *);
+static void	f_if(char *);
+static void	f_obs(char *);
+static void	f_of(char *);
+static void	f_seek(char *);
+static void	f_skip(char *);
+static void	f_progress(char *);
+
+static const struct arg {
+	const char *name;
+	void (*f)(char *);
+	u_int set, noset;
+} args[] = {
+     /* the array needs to be sorted by the first column so
+	bsearch() can be used to find commands quickly */
+	{ "bs",		f_bs,		C_BS,	 C_BS|C_IBS|C_OBS|C_OSYNC },
+	{ "cbs",	f_cbs,		C_CBS,	 C_CBS },
+	{ "conv",	f_conv,		0,	 0 },
+	{ "count",	f_count,	C_COUNT, C_COUNT },
+	{ "files",	f_files,	C_FILES, C_FILES },
+	{ "ibs",	f_ibs,		C_IBS,	 C_BS|C_IBS },
+	{ "if",		f_if,		C_IF,	 C_IF },
+	{ "iseek",	f_skip,		C_SKIP,	 C_SKIP },
+	{ "msgfmt",	f_msgfmt,	0,	 0 },
+	{ "obs",	f_obs,		C_OBS,	 C_BS|C_OBS },
+	{ "of",		f_of,		C_OF,	 C_OF },
+	{ "oseek",	f_seek,		C_SEEK,	 C_SEEK },
+	{ "progress",	f_progress,	0,	 0 },
+	{ "seek",	f_seek,		C_SEEK,	 C_SEEK },
+	{ "skip",	f_skip,		C_SKIP,	 C_SKIP },
+};
+
+/*
+ * args -- parse JCL syntax of dd.
+ */
+void
+jcl(char **argv)
+{
+	struct arg *ap, tmp;
+	char *oper, *arg;
+
+	in.dbsz = out.dbsz = 512;
+
+	while ((oper = *++argv) != NULL) {
+		if ((oper = strdup(oper)) == NULL) {
+			errx(EXIT_FAILURE,
+			    "unable to allocate space for the argument %s",
+			    *argv);
+			/* NOTREACHED */
+		}
+		if ((arg = strchr(oper, '=')) == NULL) {
+			errx(EXIT_FAILURE, "unknown operand %s", oper);
+			/* NOTREACHED */
+		}
+		*arg++ = '\0';
+		if (!*arg) {
+			errx(EXIT_FAILURE, "no value specified for %s", oper);
+			/* NOTREACHED */
+		}
+		tmp.name = oper;
+		if (!(ap = bsearch(&tmp, args,
+		    __arraycount(args), sizeof(*args), c_arg))) {
+			errx(EXIT_FAILURE, "unknown operand %s", tmp.name);
+			/* NOTREACHED */
+		}
+		if (ddflags & ap->noset) {
+			errx(EXIT_FAILURE,
+			    "%s: illegal argument combination or already set",
+			    tmp.name);
+			/* NOTREACHED */
+		}
+		ddflags |= ap->set;
+		ap->f(arg);
+	}
+
+	/* Final sanity checks. */
+
+	if (ddflags & C_BS) {
+		/*
+		 * Bs is turned off by any conversion -- we assume the user
+		 * just wanted to set both the input and output block sizes
+		 * and didn't want the bs semantics, so we don't warn.
+		 */
+		if (ddflags & (C_BLOCK | C_LCASE | C_SWAB | C_UCASE |
+		    C_UNBLOCK | C_OSYNC | C_ASCII | C_EBCDIC | C_SPARSE)) {
+			ddflags &= ~C_BS;
+			ddflags |= C_IBS|C_OBS;
+		}
+
+		/* Bs supersedes ibs and obs. */
+		if (ddflags & C_BS && ddflags & (C_IBS|C_OBS))
+			warnx("bs supersedes ibs and obs");
+	}
+
+	/*
+	 * Ascii/ebcdic and cbs implies block/unblock.
+	 * Block/unblock requires cbs and vice-versa.
+	 */
+	if (ddflags & (C_BLOCK|C_UNBLOCK)) {
+		if (!(ddflags & C_CBS)) {
+			errx(EXIT_FAILURE, "record operations require cbs");
+			/* NOTREACHED */
+		}
+		cfunc = ddflags & C_BLOCK ? block : unblock;
+	} else if (ddflags & C_CBS) {
+		if (ddflags & (C_ASCII|C_EBCDIC)) {
+			if (ddflags & C_ASCII) {
+				ddflags |= C_UNBLOCK;
+				cfunc = unblock;
+			} else {
+				ddflags |= C_BLOCK;
+				cfunc = block;
+			}
+		} else {
+			errx(EXIT_FAILURE,
+			    "cbs meaningless if not doing record operations");
+			/* NOTREACHED */
+		}
+	} else
+		cfunc = def;
+
+	/* Read, write and seek calls take off_t as arguments.
+	 *
+	 * The following check is not done because an off_t is a quad
+	 *  for current NetBSD implementations.
+	 *
+	 * if (in.offset > INT_MAX/in.dbsz || out.offset > INT_MAX/out.dbsz)
+	 *	errx(1, "seek offsets cannot be larger than %d", INT_MAX);
+	 */
+}
+
+static int
+c_arg(const void *a, const void *b)
+{
+
+	return (strcmp(((const struct arg *)a)->name,
+	    ((const struct arg *)b)->name));
+}
+
+static void
+f_bs(char *arg)
+{
+
+	in.dbsz = out.dbsz = strsuftoll("block size", arg, 1, UINT_MAX);
+}
+
+static void
+f_cbs(char *arg)
+{
+
+	cbsz = strsuftoll("conversion record size", arg, 1, UINT_MAX);
+}
+
+static void
+f_count(char *arg)
+{
+
+	cpy_cnt = strsuftoll("block count", arg, 0, LLONG_MAX);
+	if (!cpy_cnt)
+		terminate(0);
+}
+
+static void
+f_files(char *arg)
+{
+
+	files_cnt = (u_int)strsuftoll("file count", arg, 0, UINT_MAX);
+	if (!files_cnt)
+		terminate(0);
+}
+
+static void
+f_ibs(char *arg)
+{
+
+	if (!(ddflags & C_BS))
+		in.dbsz = strsuftoll("input block size", arg, 1, UINT_MAX);
+}
+
+static void
+f_if(char *arg)
+{
+
+	in.name = arg;
+}
+
+#ifdef NO_MSGFMT
+/* Build a small version (i.e. for a ramdisk root) */
+static void
+f_msgfmt(char *arg)
+{
+
+	errx(EXIT_FAILURE, "msgfmt option disabled");
+	/* NOTREACHED */
+}
+#else	/* NO_MSGFMT */
+static void
+f_msgfmt(char *arg)
+{
+
+	/*
+	 * If the format string is not valid, dd_write_msg() will print
+	 * an error and exit.
+	 */
+	dd_write_msg(arg, 0);
+
+	msgfmt = arg;
+}
+#endif	/* NO_MSGFMT */
+
+static void
+f_obs(char *arg)
+{
+
+	if (!(ddflags & C_BS))
+		out.dbsz = strsuftoll("output block size", arg, 1, UINT_MAX);
+}
+
+static void
+f_of(char *arg)
+{
+
+	out.name = arg;
+}
+
+static void
+f_seek(char *arg)
+{
+
+	out.offset = strsuftoll("seek blocks", arg, 0, LLONG_MAX);
+}
+
+static void
+f_skip(char *arg)
+{
+
+	in.offset = strsuftoll("skip blocks", arg, 0, LLONG_MAX);
+}
+
+static void
+f_progress(char *arg)
+{
+
+	progress = strsuftoll("progress blocks", arg, 0, LLONG_MAX);
+}
+
+#ifdef	NO_CONV
+/* Build a small version (i.e. for a ramdisk root) */
+static void
+f_conv(char *arg)
+{
+
+	errx(EXIT_FAILURE, "conv option disabled");
+	/* NOTREACHED */
+}
+#else	/* NO_CONV */
+
+static const struct conv {
+	const char *name;
+	u_int set, noset;
+	const u_char *ctab;
+} clist[] = {
+	{ "ascii",	C_ASCII,	C_EBCDIC,	e2a_POSIX },
+	{ "block",	C_BLOCK,	C_UNBLOCK,	NULL },
+	{ "ebcdic",	C_EBCDIC,	C_ASCII,	a2e_POSIX },
+	{ "ibm",	C_EBCDIC,	C_ASCII,	a2ibm_POSIX },
+	{ "lcase",	C_LCASE,	C_UCASE,	NULL },
+	{ "noerror",	C_NOERROR,	0,		NULL },
+	{ "notrunc",	C_NOTRUNC,	0,		NULL },
+	{ "oldascii",	C_ASCII,	C_EBCDIC,	e2a_32V },
+	{ "oldebcdic",	C_EBCDIC,	C_ASCII,	a2e_32V },
+	{ "oldibm",	C_EBCDIC,	C_ASCII,	a2ibm_32V },
+	{ "osync",	C_OSYNC,	C_BS,		NULL },
+	{ "sparse",	C_SPARSE,	0,		NULL },
+	{ "swab",	C_SWAB,		0,		NULL },
+	{ "sync",	C_SYNC,		0,		NULL },
+	{ "ucase",	C_UCASE,	C_LCASE,	NULL },
+	{ "unblock",	C_UNBLOCK,	C_BLOCK,	NULL },
+	/* If you add items to this table, be sure to add the
+	 * conversions to the C_BS check in the jcl routine above.
+	 */
+};
+
+static void
+f_conv(char *arg)
+{
+	struct conv *cp, tmp;
+
+	while (arg != NULL) {
+		tmp.name = strsep(&arg, ",");
+		if (!(cp = bsearch(&tmp, clist,
+		    __arraycount(clist), sizeof(*clist), c_conv))) {
+			errx(EXIT_FAILURE, "unknown conversion %s", tmp.name);
+			/* NOTREACHED */
+		}
+		if (ddflags & cp->noset) {
+			errx(EXIT_FAILURE,
+			    "%s: illegal conversion combination", tmp.name);
+			/* NOTREACHED */
+		}
+		ddflags |= cp->set;
+		if (cp->ctab)
+			ctab = cp->ctab;
+	}
+}
+
+static int
+c_conv(const void *a, const void *b)
+{
+
+	return (strcmp(((const struct conv *)a)->name,
+	    ((const struct conv *)b)->name));
+}
+
+#endif	/* NO_CONV */
diff --git a/toolbox/upstream-netbsd/bin/dd/conv.c b/toolbox/upstream-netbsd/bin/dd/conv.c
new file mode 100644
index 0000000..d4a8a09
--- /dev/null
+++ b/toolbox/upstream-netbsd/bin/dd/conv.c
@@ -0,0 +1,283 @@
+/*	$NetBSD: conv.c,v 1.17 2003/08/07 09:05:10 agc Exp $	*/
+
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego and Lance
+ * Visser of Convex Computer Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)conv.c	8.3 (Berkeley) 4/2/94";
+#else
+__RCSID("$NetBSD: conv.c,v 1.17 2003/08/07 09:05:10 agc Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+
+#include <err.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "dd.h"
+#include "extern.h"
+
+/*
+ * def --
+ * Copy input to output.  Input is buffered until reaches obs, and then
+ * output until less than obs remains.  Only a single buffer is used.
+ * Worst case buffer calculation is (ibs + obs - 1).
+ */
+void
+def(void)
+{
+	uint64_t cnt;
+	u_char *inp;
+	const u_char *t;
+
+	if ((t = ctab) != NULL)
+		for (inp = in.dbp - (cnt = in.dbrcnt); cnt--; ++inp)
+			*inp = t[*inp];
+
+	/* Make the output buffer look right. */
+	out.dbp = in.dbp;
+	out.dbcnt = in.dbcnt;
+
+	if (in.dbcnt >= out.dbsz) {
+		/* If the output buffer is full, write it. */
+		dd_out(0);
+
+		/*
+		 * Ddout copies the leftover output to the beginning of
+		 * the buffer and resets the output buffer.  Reset the
+		 * input buffer to match it.
+	 	 */
+		in.dbp = out.dbp;
+		in.dbcnt = out.dbcnt;
+	}
+}
+
+void
+def_close(void)
+{
+
+	/* Just update the count, everything is already in the buffer. */
+	if (in.dbcnt)
+		out.dbcnt = in.dbcnt;
+}
+
+#ifdef	NO_CONV
+/* Build a smaller version (i.e. for a miniroot) */
+/* These can not be called, but just in case...  */
+static const char no_block[] = "unblock and -DNO_CONV?";
+void block(void)		{ errx(EXIT_FAILURE, "%s", no_block + 2); }
+void block_close(void)		{ errx(EXIT_FAILURE, "%s", no_block + 2); }
+void unblock(void)		{ errx(EXIT_FAILURE, "%s", no_block); }
+void unblock_close(void)	{ errx(EXIT_FAILURE, "%s", no_block); }
+#else	/* NO_CONV */
+
+/*
+ * Copy variable length newline terminated records with a max size cbsz
+ * bytes to output.  Records less than cbs are padded with spaces.
+ *
+ * max in buffer:  MAX(ibs, cbsz)
+ * max out buffer: obs + cbsz
+ */
+void
+block(void)
+{
+	static int intrunc;
+	int ch = 0;	/* pacify gcc */
+	uint64_t cnt, maxlen;
+	u_char *inp, *outp;
+	const u_char *t;
+
+	/*
+	 * Record truncation can cross block boundaries.  If currently in a
+	 * truncation state, keep tossing characters until reach a newline.
+	 * Start at the beginning of the buffer, as the input buffer is always
+	 * left empty.
+	 */
+	if (intrunc) {
+		for (inp = in.db, cnt = in.dbrcnt;
+		    cnt && *inp++ != '\n'; --cnt);
+		if (!cnt) {
+			in.dbcnt = 0;
+			in.dbp = in.db;
+			return;
+		}
+		intrunc = 0;
+		/* Adjust the input buffer numbers. */
+		in.dbcnt = cnt - 1;
+		in.dbp = inp + cnt - 1;
+	}
+
+	/*
+	 * Copy records (max cbsz size chunks) into the output buffer.  The
+	 * translation is done as we copy into the output buffer.
+	 */
+	for (inp = in.dbp - in.dbcnt, outp = out.dbp; in.dbcnt;) {
+		maxlen = MIN(cbsz, in.dbcnt);
+		if ((t = ctab) != NULL)
+			for (cnt = 0;
+			    cnt < maxlen && (ch = *inp++) != '\n'; ++cnt)
+				*outp++ = t[ch];
+		else
+			for (cnt = 0;
+			    cnt < maxlen && (ch = *inp++) != '\n'; ++cnt)
+				*outp++ = ch;
+		/*
+		 * Check for short record without a newline.  Reassemble the
+		 * input block.
+		 */
+		if (ch != '\n' && in.dbcnt < cbsz) {
+			(void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt);
+			break;
+		}
+
+		/* Adjust the input buffer numbers. */
+		in.dbcnt -= cnt;
+		if (ch == '\n')
+			--in.dbcnt;
+
+		/* Pad short records with spaces. */
+		if (cnt < cbsz)
+			(void)memset(outp, ctab ? ctab[' '] : ' ', cbsz - cnt);
+		else {
+			/*
+			 * If the next character wouldn't have ended the
+			 * block, it's a truncation.
+			 */
+			if (!in.dbcnt || *inp != '\n')
+				++st.trunc;
+
+			/* Toss characters to a newline. */
+			for (; in.dbcnt && *inp++ != '\n'; --in.dbcnt);
+			if (!in.dbcnt)
+				intrunc = 1;
+			else
+				--in.dbcnt;
+		}
+
+		/* Adjust output buffer numbers. */
+		out.dbp += cbsz;
+		if ((out.dbcnt += cbsz) >= out.dbsz)
+			dd_out(0);
+		outp = out.dbp;
+	}
+	in.dbp = in.db + in.dbcnt;
+}
+
+void
+block_close(void)
+{
+
+	/*
+	 * Copy any remaining data into the output buffer and pad to a record.
+	 * Don't worry about truncation or translation, the input buffer is
+	 * always empty when truncating, and no characters have been added for
+	 * translation.  The bottom line is that anything left in the input
+	 * buffer is a truncated record.  Anything left in the output buffer
+	 * just wasn't big enough.
+	 */
+	if (in.dbcnt) {
+		++st.trunc;
+		(void)memmove(out.dbp, in.dbp - in.dbcnt, in.dbcnt);
+		(void)memset(out.dbp + in.dbcnt,
+		    ctab ? ctab[' '] : ' ', cbsz - in.dbcnt);
+		out.dbcnt += cbsz;
+	}
+}
+
+/*
+ * Convert fixed length (cbsz) records to variable length.  Deletes any
+ * trailing blanks and appends a newline.
+ *
+ * max in buffer:  MAX(ibs, cbsz) + cbsz
+ * max out buffer: obs + cbsz
+ */
+void
+unblock(void)
+{
+	uint64_t cnt;
+	u_char *inp;
+	const u_char *t;
+
+	/* Translation and case conversion. */
+	if ((t = ctab) != NULL)
+		for (cnt = in.dbrcnt, inp = in.dbp - 1; cnt--; inp--)
+			*inp = t[*inp];
+	/*
+	 * Copy records (max cbsz size chunks) into the output buffer.  The
+	 * translation has to already be done or we might not recognize the
+	 * spaces.
+	 */
+	for (inp = in.db; in.dbcnt >= cbsz; inp += cbsz, in.dbcnt -= cbsz) {
+		for (t = inp + cbsz - 1; t >= inp && *t == ' '; --t);
+		if (t >= inp) {
+			cnt = t - inp + 1;
+			(void)memmove(out.dbp, inp, cnt);
+			out.dbp += cnt;
+			out.dbcnt += cnt;
+		}
+		++out.dbcnt;
+		*out.dbp++ = '\n';
+		if (out.dbcnt >= out.dbsz)
+			dd_out(0);
+	}
+	if (in.dbcnt)
+		(void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt);
+	in.dbp = in.db + in.dbcnt;
+}
+
+void
+unblock_close(void)
+{
+	uint64_t cnt;
+	u_char *t;
+
+	if (in.dbcnt) {
+		warnx("%s: short input record", in.name);
+		for (t = in.db + in.dbcnt - 1; t >= in.db && *t == ' '; --t);
+		if (t >= in.db) {
+			cnt = t - in.db + 1;
+			(void)memmove(out.dbp, in.db, cnt);
+			out.dbp += cnt;
+			out.dbcnt += cnt;
+		}
+		++out.dbcnt;
+		*out.dbp++ = '\n';
+	}
+}
+
+#endif	/* NO_CONV */
diff --git a/toolbox/upstream-netbsd/bin/dd/dd.c b/toolbox/upstream-netbsd/bin/dd/dd.c
new file mode 100644
index 0000000..03d080c
--- /dev/null
+++ b/toolbox/upstream-netbsd/bin/dd/dd.c
@@ -0,0 +1,598 @@
+/*	$NetBSD: dd.c,v 1.49 2012/02/21 01:49:01 matt Exp $	*/
+
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego and Lance
+ * Visser of Convex Computer Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1991, 1993, 1994\
+ The Regents of the University of California.  All rights reserved.");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)dd.c	8.5 (Berkeley) 4/2/94";
+#else
+__RCSID("$NetBSD: dd.c,v 1.49 2012/02/21 01:49:01 matt Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mtio.h>
+#include <sys/time.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <locale.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "dd.h"
+#include "extern.h"
+
+static void dd_close(void);
+static void dd_in(void);
+static void getfdtype(IO *);
+static void redup_clean_fd(IO *);
+static void setup(void);
+
+int main(int, char *[]);
+
+IO		in, out;		/* input/output state */
+STAT		st;			/* statistics */
+void		(*cfunc)(void);		/* conversion function */
+uint64_t	cpy_cnt;		/* # of blocks to copy */
+static off_t	pending = 0;		/* pending seek if sparse */
+u_int		ddflags;		/* conversion options */
+uint64_t	cbsz;			/* conversion block size */
+u_int		files_cnt = 1;		/* # of files to copy */
+uint64_t	progress = 0;		/* display sign of life */
+const u_char	*ctab;			/* conversion table */
+sigset_t	infoset;		/* a set blocking SIGINFO */
+const char	*msgfmt = "posix";	/* default summary() message format */
+
+/*
+ * Ops for stdin/stdout and crunch'd dd.  These are always host ops.
+ */
+static const struct ddfops ddfops_stdfd = {
+	.op_open = open,
+	.op_close = close,
+	.op_fcntl = fcntl,
+	.op_ioctl = ioctl,
+	.op_fstat = fstat,
+	.op_fsync = fsync,
+	.op_ftruncate = ftruncate,
+	.op_lseek = lseek,
+	.op_read = read,
+	.op_write = write,
+};
+extern const struct ddfops ddfops_prog;
+
+int
+main(int argc, char *argv[])
+{
+	int ch;
+
+	setprogname(argv[0]);
+	(void)setlocale(LC_ALL, "");
+
+	while ((ch = getopt(argc, argv, "")) != -1) {
+		switch (ch) {
+		default:
+			errx(EXIT_FAILURE, "usage: dd [operand ...]");
+			/* NOTREACHED */
+		}
+	}
+	argc -= (optind - 1);
+	argv += (optind - 1);
+
+	jcl(argv);
+#ifndef CRUNCHOPS
+	if (ddfops_prog.op_init && ddfops_prog.op_init() == -1)
+		err(1, "prog init");
+#endif
+	setup();
+
+	(void)signal(SIGINFO, summaryx);
+	(void)signal(SIGINT, terminate);
+	(void)sigemptyset(&infoset);
+	(void)sigaddset(&infoset, SIGINFO);
+
+	(void)atexit(summary);
+
+	while (files_cnt--)
+		dd_in();
+
+	dd_close();
+	exit(0);
+	/* NOTREACHED */
+}
+
+static void
+setup(void)
+{
+#ifdef CRUNCHOPS
+	const struct ddfops *prog_ops = &ddfops_stdfd;
+#else
+	const struct ddfops *prog_ops = &ddfops_prog;
+#endif
+
+	if (in.name == NULL) {
+		in.name = "stdin";
+		in.fd = STDIN_FILENO;
+		in.ops = &ddfops_stdfd;
+	} else {
+		in.ops = prog_ops;
+		in.fd = ddop_open(in, in.name, O_RDONLY, 0);
+		if (in.fd < 0)
+			err(EXIT_FAILURE, "%s", in.name);
+			/* NOTREACHED */
+
+		/* Ensure in.fd is outside the stdio descriptor range */
+		redup_clean_fd(&in);
+	}
+
+	getfdtype(&in);
+
+	if (files_cnt > 1 && !(in.flags & ISTAPE)) {
+		errx(EXIT_FAILURE, "files is not supported for non-tape devices");
+		/* NOTREACHED */
+	}
+
+	if (out.name == NULL) {
+		/* No way to check for read access here. */
+		out.fd = STDOUT_FILENO;
+		out.name = "stdout";
+		out.ops = &ddfops_stdfd;
+	} else {
+		out.ops = prog_ops;
+#define	OFLAGS \
+    (O_CREAT | (ddflags & (C_SEEK | C_NOTRUNC) ? 0 : O_TRUNC))
+		out.fd = ddop_open(out, out.name, O_RDWR | OFLAGS, DEFFILEMODE);
+		/*
+		 * May not have read access, so try again with write only.
+		 * Without read we may have a problem if output also does
+		 * not support seeks.
+		 */
+		if (out.fd < 0) {
+			out.fd = ddop_open(out, out.name, O_WRONLY | OFLAGS,
+			    DEFFILEMODE);
+			out.flags |= NOREAD;
+		}
+		if (out.fd < 0) {
+			err(EXIT_FAILURE, "%s", out.name);
+			/* NOTREACHED */
+		}
+
+		/* Ensure out.fd is outside the stdio descriptor range */
+		redup_clean_fd(&out);
+	}
+
+	getfdtype(&out);
+
+	/*
+	 * Allocate space for the input and output buffers.  If not doing
+	 * record oriented I/O, only need a single buffer.
+	 */
+	if (!(ddflags & (C_BLOCK|C_UNBLOCK))) {
+		size_t dbsz = out.dbsz;
+		if (!(ddflags & C_BS))
+			dbsz += in.dbsz - 1;
+		if ((in.db = malloc(dbsz)) == NULL) {
+			err(EXIT_FAILURE, NULL);
+			/* NOTREACHED */
+		}
+		out.db = in.db;
+	} else if ((in.db =
+	    malloc((u_int)(MAX(in.dbsz, cbsz) + cbsz))) == NULL ||
+	    (out.db = malloc((u_int)(out.dbsz + cbsz))) == NULL) {
+		err(EXIT_FAILURE, NULL);
+		/* NOTREACHED */
+	}
+	in.dbp = in.db;
+	out.dbp = out.db;
+
+	/* Position the input/output streams. */
+	if (in.offset)
+		pos_in();
+	if (out.offset)
+		pos_out();
+
+	/*
+	 * Truncate the output file; ignore errors because it fails on some
+	 * kinds of output files, tapes, for example.
+	 */
+	if ((ddflags & (C_OF | C_SEEK | C_NOTRUNC)) == (C_OF | C_SEEK))
+		(void)ddop_ftruncate(out, out.fd, (off_t)out.offset * out.dbsz);
+
+	/*
+	 * If converting case at the same time as another conversion, build a
+	 * table that does both at once.  If just converting case, use the
+	 * built-in tables.
+	 */
+	if (ddflags & (C_LCASE|C_UCASE)) {
+#ifdef	NO_CONV
+		/* Should not get here, but just in case... */
+		errx(EXIT_FAILURE, "case conv and -DNO_CONV");
+		/* NOTREACHED */
+#else	/* NO_CONV */
+		u_int cnt;
+
+		if (ddflags & C_ASCII || ddflags & C_EBCDIC) {
+			if (ddflags & C_LCASE) {
+				for (cnt = 0; cnt < 256; ++cnt)
+					casetab[cnt] = tolower(ctab[cnt]);
+			} else {
+				for (cnt = 0; cnt < 256; ++cnt)
+					casetab[cnt] = toupper(ctab[cnt]);
+			}
+		} else {
+			if (ddflags & C_LCASE) {
+				for (cnt = 0; cnt < 256; ++cnt)
+					casetab[cnt] = tolower(cnt);
+			} else {
+				for (cnt = 0; cnt < 256; ++cnt)
+					casetab[cnt] = toupper(cnt);
+			}
+		}
+
+		ctab = casetab;
+#endif	/* NO_CONV */
+	}
+
+	(void)gettimeofday(&st.start, NULL);	/* Statistics timestamp. */
+}
+
+static void
+getfdtype(IO *io)
+{
+	struct mtget mt;
+	struct stat sb;
+
+	if (io->ops->op_fstat(io->fd, &sb)) {
+		err(EXIT_FAILURE, "%s", io->name);
+		/* NOTREACHED */
+	}
+	if (S_ISCHR(sb.st_mode))
+		io->flags |= io->ops->op_ioctl(io->fd, MTIOCGET, &mt)
+		    ? ISCHR : ISTAPE;
+	else if (io->ops->op_lseek(io->fd, (off_t)0, SEEK_CUR) == -1
+	    && errno == ESPIPE)
+		io->flags |= ISPIPE;		/* XXX fixed in 4.4BSD */
+}
+
+/*
+ * Move the parameter file descriptor to a descriptor that is outside the
+ * stdio descriptor range, if necessary.  This is required to avoid
+ * accidentally outputting completion or error messages into the
+ * output file that were intended for the tty.
+ */
+static void
+redup_clean_fd(IO *io)
+{
+	int fd = io->fd;
+	int newfd;
+
+	if (fd != STDIN_FILENO && fd != STDOUT_FILENO &&
+	    fd != STDERR_FILENO)
+		/* File descriptor is ok, return immediately. */
+		return;
+
+	/*
+	 * 3 is the first descriptor greater than STD*_FILENO.  Any
+	 * free descriptor valued 3 or above is acceptable...
+	 */
+	newfd = io->ops->op_fcntl(fd, F_DUPFD, 3);
+	if (newfd < 0) {
+		err(EXIT_FAILURE, "dupfd IO");
+		/* NOTREACHED */
+	}
+
+	io->ops->op_close(fd);
+	io->fd = newfd;
+}
+
+static void
+dd_in(void)
+{
+	int flags;
+	int64_t n;
+
+	for (flags = ddflags;;) {
+		if (cpy_cnt && (st.in_full + st.in_part) >= cpy_cnt)
+			return;
+
+		/*
+		 * Clear the buffer first if doing "sync" on input.
+		 * If doing block operations use spaces.  This will
+		 * affect not only the C_NOERROR case, but also the
+		 * last partial input block which should be padded
+		 * with zero and not garbage.
+		 */
+		if (flags & C_SYNC) {
+			if (flags & (C_BLOCK|C_UNBLOCK))
+				(void)memset(in.dbp, ' ', in.dbsz);
+			else
+				(void)memset(in.dbp, 0, in.dbsz);
+		}
+
+		n = ddop_read(in, in.fd, in.dbp, in.dbsz);
+		if (n == 0) {
+			in.dbrcnt = 0;
+			return;
+		}
+
+		/* Read error. */
+		if (n < 0) {
+
+			/*
+			 * If noerror not specified, die.  POSIX requires that
+			 * the warning message be followed by an I/O display.
+			 */
+			if (!(flags & C_NOERROR)) {
+				err(EXIT_FAILURE, "%s", in.name);
+				/* NOTREACHED */
+			}
+			warn("%s", in.name);
+			summary();
+
+			/*
+			 * If it's not a tape drive or a pipe, seek past the
+			 * error.  If your OS doesn't do the right thing for
+			 * raw disks this section should be modified to re-read
+			 * in sector size chunks.
+			 */
+			if (!(in.flags & (ISPIPE|ISTAPE)) &&
+			    ddop_lseek(in, in.fd, (off_t)in.dbsz, SEEK_CUR))
+				warn("%s", in.name);
+
+			/* If sync not specified, omit block and continue. */
+			if (!(ddflags & C_SYNC))
+				continue;
+
+			/* Read errors count as full blocks. */
+			in.dbcnt += in.dbrcnt = in.dbsz;
+			++st.in_full;
+
+		/* Handle full input blocks. */
+		} else if ((uint64_t)n == in.dbsz) {
+			in.dbcnt += in.dbrcnt = n;
+			++st.in_full;
+
+		/* Handle partial input blocks. */
+		} else {
+			/* If sync, use the entire block. */
+			if (ddflags & C_SYNC)
+				in.dbcnt += in.dbrcnt = in.dbsz;
+			else
+				in.dbcnt += in.dbrcnt = n;
+			++st.in_part;
+		}
+
+		/*
+		 * POSIX states that if bs is set and no other conversions
+		 * than noerror, notrunc or sync are specified, the block
+		 * is output without buffering as it is read.
+		 */
+		if (ddflags & C_BS) {
+			out.dbcnt = in.dbcnt;
+			dd_out(1);
+			in.dbcnt = 0;
+			continue;
+		}
+
+		if (ddflags & C_SWAB) {
+			if ((n = in.dbrcnt) & 1) {
+				++st.swab;
+				--n;
+			}
+			swab(in.dbp, in.dbp, n);
+		}
+
+		in.dbp += in.dbrcnt;
+		(*cfunc)();
+	}
+}
+
+/*
+ * Cleanup any remaining I/O and flush output.  If necessary, output file
+ * is truncated.
+ */
+static void
+dd_close(void)
+{
+
+	if (cfunc == def)
+		def_close();
+	else if (cfunc == block)
+		block_close();
+	else if (cfunc == unblock)
+		unblock_close();
+	if (ddflags & C_OSYNC && out.dbcnt < out.dbsz) {
+		(void)memset(out.dbp, 0, out.dbsz - out.dbcnt);
+		out.dbcnt = out.dbsz;
+	}
+	/* If there are pending sparse blocks, make sure
+	 * to write out the final block un-sparse
+	 */
+	if ((out.dbcnt == 0) && pending) {
+		memset(out.db, 0, out.dbsz);
+		out.dbcnt = out.dbsz;
+		out.dbp = out.db + out.dbcnt;
+		pending -= out.dbsz;
+	}
+	if (out.dbcnt)
+		dd_out(1);
+
+	/*
+	 * Reporting nfs write error may be deferred until next
+	 * write(2) or close(2) system call.  So, we need to do an
+	 * extra check.  If an output is stdout, the file structure
+	 * may be shared with other processes and close(2) just
+	 * decreases the reference count.
+	 */
+	if (out.fd == STDOUT_FILENO && ddop_fsync(out, out.fd) == -1
+	    && errno != EINVAL) {
+		err(EXIT_FAILURE, "fsync stdout");
+		/* NOTREACHED */
+	}
+	if (ddop_close(out, out.fd) == -1) {
+		err(EXIT_FAILURE, "close");
+		/* NOTREACHED */
+	}
+}
+
+void
+dd_out(int force)
+{
+	static int warned;
+	int64_t cnt, n, nw;
+	u_char *outp;
+
+	/*
+	 * Write one or more blocks out.  The common case is writing a full
+	 * output block in a single write; increment the full block stats.
+	 * Otherwise, we're into partial block writes.  If a partial write,
+	 * and it's a character device, just warn.  If a tape device, quit.
+	 *
+	 * The partial writes represent two cases.  1: Where the input block
+	 * was less than expected so the output block was less than expected.
+	 * 2: Where the input block was the right size but we were forced to
+	 * write the block in multiple chunks.  The original versions of dd(1)
+	 * never wrote a block in more than a single write, so the latter case
+	 * never happened.
+	 *
+	 * One special case is if we're forced to do the write -- in that case
+	 * we play games with the buffer size, and it's usually a partial write.
+	 */
+	outp = out.db;
+	for (n = force ? out.dbcnt : out.dbsz;; n = out.dbsz) {
+		for (cnt = n;; cnt -= nw) {
+
+			if (!force && ddflags & C_SPARSE) {
+				int sparse, i;
+				sparse = 1;	/* Is buffer sparse? */
+				for (i = 0; i < cnt; i++)
+					if (outp[i] != 0) {
+						sparse = 0;
+						break;
+					}
+				if (sparse) {
+					pending += cnt;
+					outp += cnt;
+					nw = 0;
+					break;
+				}
+			}
+			if (pending != 0) {
+				if (ddop_lseek(out,
+				    out.fd, pending, SEEK_CUR) == -1)
+					err(EXIT_FAILURE, "%s: seek error creating sparse file",
+					    out.name);
+			}
+			nw = bwrite(&out, outp, cnt);
+			if (nw <= 0) {
+				if (nw == 0)
+					errx(EXIT_FAILURE,
+						"%s: end of device", out.name);
+					/* NOTREACHED */
+				if (errno != EINTR)
+					err(EXIT_FAILURE, "%s", out.name);
+					/* NOTREACHED */
+				nw = 0;
+			}
+			if (pending) {
+				st.bytes += pending;
+				st.sparse += pending/out.dbsz;
+				st.out_full += pending/out.dbsz;
+				pending = 0;
+			}
+			outp += nw;
+			st.bytes += nw;
+			if (nw == n) {
+				if ((uint64_t)n != out.dbsz)
+					++st.out_part;
+				else
+					++st.out_full;
+				break;
+			}
+			++st.out_part;
+			if (nw == cnt)
+				break;
+			if (out.flags & ISCHR && !warned) {
+				warned = 1;
+				warnx("%s: short write on character device", out.name);
+			}
+			if (out.flags & ISTAPE)
+				errx(EXIT_FAILURE,
+					"%s: short write on tape device", out.name);
+				/* NOTREACHED */
+
+		}
+		if ((out.dbcnt -= n) < out.dbsz)
+			break;
+	}
+
+	/* Reassemble the output block. */
+	if (out.dbcnt)
+		(void)memmove(out.db, out.dbp - out.dbcnt, out.dbcnt);
+	out.dbp = out.db + out.dbcnt;
+
+	if (progress && (st.out_full + st.out_part) % progress == 0)
+		(void)write(STDERR_FILENO, ".", 1);
+}
+
+/*
+ * A protected against SIGINFO write
+ */
+ssize_t
+bwrite(IO *io, const void *buf, size_t len)
+{
+	sigset_t oset;
+	ssize_t rv;
+	int oerrno;
+
+	(void)sigprocmask(SIG_BLOCK, &infoset, &oset);
+	rv = io->ops->op_write(io->fd, buf, len);
+	oerrno = errno;
+	(void)sigprocmask(SIG_SETMASK, &oset, NULL);
+	errno = oerrno;
+	return (rv);
+}
diff --git a/toolbox/dd.h b/toolbox/upstream-netbsd/bin/dd/dd.h
similarity index 74%
rename from toolbox/dd.h
rename to toolbox/upstream-netbsd/bin/dd/dd.h
index 89f2833..b01c7b3 100644
--- a/toolbox/dd.h
+++ b/toolbox/upstream-netbsd/bin/dd/dd.h
@@ -1,4 +1,4 @@
-/*	$NetBSD: dd.h,v 1.12 2004/01/17 20:48:57 dbj Exp $	*/
+/*	$NetBSD: dd.h,v 1.15 2011/02/04 19:42:12 pooka Exp $	*/
 
 /*-
  * Copyright (c) 1991, 1993, 1994
@@ -35,7 +35,40 @@
  *	@(#)dd.h	8.3 (Berkeley) 4/2/94
  */
 
-#include <stdint.h>
+#include <sys/stat.h>
+
+struct ddfops {
+	int (*op_init)(void);
+
+	int (*op_open)(const char *, int, ...);
+	int (*op_close)(int);
+
+	int (*op_fcntl)(int, int, ...);
+#ifdef __ANDROID__
+	int (*op_ioctl)(int, int, ...);
+#else
+	int (*op_ioctl)(int, unsigned long, ...);
+#endif
+
+	int (*op_fstat)(int, struct stat *);
+	int (*op_fsync)(int);
+	int (*op_ftruncate)(int, off_t);
+
+	off_t (*op_lseek)(int, off_t, int);
+
+	ssize_t (*op_read)(int, void *, size_t);
+	ssize_t (*op_write)(int, const void *, size_t);
+};
+
+#define ddop_open(dir, a1, a2, ...)	dir.ops->op_open(a1, a2, __VA_ARGS__)
+#define ddop_close(dir, a1)		dir.ops->op_close(a1)
+#define ddop_fcntl(dir, a1, a2, ...)	dir.ops->op_fcntl(a1, a2, __VA_ARGS__)
+#define ddop_ioctl(dir, a1, a2, ...)	dir.ops->op_ioctl(a1, a2, __VA_ARGS__)
+#define ddop_fsync(dir, a1)		dir.ops->op_fsync(a1)
+#define ddop_ftruncate(dir, a1, a2)	dir.ops->op_ftruncate(a1, a2)
+#define ddop_lseek(dir, a1, a2, a3)	dir.ops->op_lseek(a1, a2, a3)
+#define ddop_read(dir, a1, a2, a3)	dir.ops->op_read(a1, a2, a3)
+#define ddop_write(dir, a1, a2, a3)	dir.ops->op_write(a1, a2, a3)
 
 /* Input/output stream state. */
 typedef struct {
@@ -54,6 +87,7 @@
 	const char  	*name;		/* name */
 	int		fd;		/* file descriptor */
 	uint64_t	offset;		/* # of blocks to skip */
+	struct ddfops	const *ops;	/* ops to use with fd */
 } IO;
 
 typedef struct {
@@ -91,4 +125,3 @@
 #define	C_UNBLOCK	0x80000
 #define	C_OSYNC		0x100000
 #define	C_SPARSE	0x200000
-#define	C_FDATASYNC	0x400000
diff --git a/toolbox/upstream-netbsd/bin/dd/dd_hostops.c b/toolbox/upstream-netbsd/bin/dd/dd_hostops.c
new file mode 100644
index 0000000..d6e7a89
--- /dev/null
+++ b/toolbox/upstream-netbsd/bin/dd/dd_hostops.c
@@ -0,0 +1,53 @@
+/*      $NetBSD: dd_hostops.c,v 1.1 2011/02/04 19:42:12 pooka Exp $	*/
+
+/*-
+ * Copyright (c) 2010 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: dd_hostops.c,v 1.1 2011/02/04 19:42:12 pooka Exp $");
+#endif /* !lint */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "dd.h"
+
+const struct ddfops ddfops_prog = {
+	.op_open = open,
+	.op_close = close,
+	.op_fcntl = fcntl,
+	.op_ioctl = ioctl,
+	.op_fstat = fstat,
+	.op_fsync = fsync,
+	.op_ftruncate = ftruncate,
+	.op_lseek = lseek,
+	.op_read = read,
+	.op_write = write,
+};
diff --git a/toolbox/upstream-netbsd/bin/dd/extern.h b/toolbox/upstream-netbsd/bin/dd/extern.h
new file mode 100644
index 0000000..9c59021
--- /dev/null
+++ b/toolbox/upstream-netbsd/bin/dd/extern.h
@@ -0,0 +1,82 @@
+/*	$NetBSD: extern.h,v 1.22 2011/11/07 22:24:23 jym Exp $	*/
+
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego and Lance
+ * Visser of Convex Computer Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)extern.h	8.3 (Berkeley) 4/2/94
+ */
+
+#include <sys/cdefs.h>
+
+#ifdef NO_CONV
+__dead void block(void);
+__dead void block_close(void);
+__dead void unblock(void);
+__dead void unblock_close(void);
+#else
+void block(void);
+void block_close(void);
+void unblock(void);
+void unblock_close(void);
+#endif
+
+#ifndef NO_MSGFMT
+int dd_write_msg(const char *, int);
+#endif
+
+void dd_out(int);
+void def(void);
+void def_close(void);
+void jcl(char **);
+void pos_in(void);
+void pos_out(void);
+void summary(void);
+void summaryx(int);
+__dead void terminate(int);
+void unblock(void);
+void unblock_close(void);
+ssize_t bwrite(IO *, const void *, size_t);
+
+extern IO		in, out;
+extern STAT		st;
+extern void		(*cfunc)(void);
+extern uint64_t		cpy_cnt;
+extern uint64_t		cbsz;
+extern u_int		ddflags;
+extern u_int		files_cnt;
+extern uint64_t		progress;
+extern const u_char	*ctab;
+extern const u_char	a2e_32V[], a2e_POSIX[];
+extern const u_char	e2a_32V[], e2a_POSIX[];
+extern const u_char	a2ibm_32V[], a2ibm_POSIX[];
+extern u_char		casetab[];
+extern const char	*msgfmt;
diff --git a/toolbox/upstream-netbsd/bin/dd/misc.c b/toolbox/upstream-netbsd/bin/dd/misc.c
new file mode 100644
index 0000000..0fac98b
--- /dev/null
+++ b/toolbox/upstream-netbsd/bin/dd/misc.c
@@ -0,0 +1,342 @@
+/*	$NetBSD: misc.c,v 1.23 2011/11/07 22:24:23 jym Exp $	*/
+
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego and Lance
+ * Visser of Convex Computer Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)misc.c	8.3 (Berkeley) 4/2/94";
+#else
+__RCSID("$NetBSD: misc.c,v 1.23 2011/11/07 22:24:23 jym Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <util.h>
+#include <inttypes.h>
+
+#include "dd.h"
+#include "extern.h"
+
+#define	tv2mS(tv) ((tv).tv_sec * 1000LL + ((tv).tv_usec + 500) / 1000)
+
+static void posix_summary(void);
+#ifndef NO_MSGFMT
+static void custom_summary(void);
+static void human_summary(void);
+static void quiet_summary(void);
+
+static void buffer_write(const char *, size_t, int);
+#endif /* NO_MSGFMT */
+
+void
+summary(void)
+{
+
+	if (progress)
+		(void)write(STDERR_FILENO, "\n", 1);
+
+#ifdef NO_MSGFMT
+	return posix_summary();
+#else /* NO_MSGFMT */
+	if (strncmp(msgfmt, "human", sizeof("human")) == 0)
+		return human_summary();
+
+	if (strncmp(msgfmt, "posix", sizeof("posix")) == 0)
+		return posix_summary();
+
+	if (strncmp(msgfmt, "quiet", sizeof("quiet")) == 0)
+		return quiet_summary();
+
+	return custom_summary();
+#endif /* NO_MSGFMT */
+}
+
+static void
+posix_summary(void)
+{
+	char buf[100];
+	int64_t mS;
+	struct timeval tv;
+
+	if (progress)
+		(void)write(STDERR_FILENO, "\n", 1);
+
+	(void)gettimeofday(&tv, NULL);
+	mS = tv2mS(tv) - tv2mS(st.start);
+	if (mS == 0)
+		mS = 1;
+
+	/* Use snprintf(3) so that we don't reenter stdio(3). */
+	(void)snprintf(buf, sizeof(buf),
+	    "%llu+%llu records in\n%llu+%llu records out\n",
+	    (unsigned long long)st.in_full,  (unsigned long long)st.in_part,
+	    (unsigned long long)st.out_full, (unsigned long long)st.out_part);
+	(void)write(STDERR_FILENO, buf, strlen(buf));
+	if (st.swab) {
+		(void)snprintf(buf, sizeof(buf), "%llu odd length swab %s\n",
+		    (unsigned long long)st.swab,
+		    (st.swab == 1) ? "block" : "blocks");
+		(void)write(STDERR_FILENO, buf, strlen(buf));
+	}
+	if (st.trunc) {
+		(void)snprintf(buf, sizeof(buf), "%llu truncated %s\n",
+		    (unsigned long long)st.trunc,
+		    (st.trunc == 1) ? "block" : "blocks");
+		(void)write(STDERR_FILENO, buf, strlen(buf));
+	}
+	if (st.sparse) {
+		(void)snprintf(buf, sizeof(buf), "%llu sparse output %s\n",
+		    (unsigned long long)st.sparse,
+		    (st.sparse == 1) ? "block" : "blocks");
+		(void)write(STDERR_FILENO, buf, strlen(buf));
+	}
+	(void)snprintf(buf, sizeof(buf),
+	    "%llu bytes transferred in %lu.%03d secs (%llu bytes/sec)\n",
+	    (unsigned long long) st.bytes,
+	    (long) (mS / 1000),
+	    (int) (mS % 1000),
+	    (unsigned long long) (st.bytes * 1000LL / mS));
+	(void)write(STDERR_FILENO, buf, strlen(buf));
+}
+
+/* ARGSUSED */
+void
+summaryx(int notused)
+{
+
+	summary();
+}
+
+/* ARGSUSED */
+void
+terminate(int signo)
+{
+
+	summary();
+	(void)raise_default_signal(signo);
+	_exit(127);
+}
+
+#ifndef NO_MSGFMT
+/*
+ * Buffer write(2) calls
+ */
+static void
+buffer_write(const char *str, size_t size, int flush)
+{
+	static char wbuf[128];
+	static size_t cnt = 0; /* Internal counter to allow wbuf to wrap */
+	
+	unsigned int i;
+
+	for (i = 0; i < size; i++) {
+		if (str != NULL) {
+			wbuf[cnt++] = str[i];
+		}
+		if (cnt >= sizeof(wbuf)) {
+			(void)write(STDERR_FILENO, wbuf, cnt);
+			cnt = 0;
+		}
+	}
+
+	if (flush != 0) {
+		(void)write(STDERR_FILENO, wbuf, cnt);
+		cnt = 0;
+	}
+}
+
+/*
+ * Write summary to stderr according to format 'fmt'. If 'enable' is 0, it
+ * will not attempt to write anything. Can be used to validate the
+ * correctness of the 'fmt' string.
+ */
+int
+dd_write_msg(const char *fmt, int enable)
+{
+	char hbuf[7], nbuf[32];
+	const char *ptr;
+	int64_t mS;
+	struct timeval tv;
+
+	(void)gettimeofday(&tv, NULL);
+	mS = tv2mS(tv) - tv2mS(st.start);
+	if (mS == 0)
+		mS = 1;
+
+#define ADDC(c) do { if (enable != 0) buffer_write(&c, 1, 0); } \
+	while (/*CONSTCOND*/0)
+#define ADDS(p) do { if (enable != 0) buffer_write(p, strlen(p), 0); } \
+	while (/*CONSTCOND*/0)
+
+	for (ptr = fmt; *ptr; ptr++) {
+		if (*ptr != '%') {
+			ADDC(*ptr);
+			continue;
+		}
+
+ 		switch (*++ptr) {
+		case 'b':
+			(void)snprintf(nbuf, sizeof(nbuf), "%llu",
+			    (unsigned long long)st.bytes);
+			ADDS(nbuf);
+			break;
+		case 'B':
+			if (humanize_number(hbuf, sizeof(hbuf),
+			    st.bytes, "B",
+			    HN_AUTOSCALE, HN_DECIMAL) == -1)
+				warnx("humanize_number (bytes transferred)");
+			ADDS(hbuf);
+			break;
+		case 'e':
+			(void)snprintf(nbuf, sizeof(nbuf), "%llu",
+			    (unsigned long long) (st.bytes * 1000LL / mS));
+			ADDS(nbuf);
+			break;
+		case 'E':
+			if (humanize_number(hbuf, sizeof(hbuf),
+			    st.bytes * 1000LL / mS, "B",
+			    HN_AUTOSCALE, HN_DECIMAL) == -1)
+				warnx("humanize_number (bytes per second)");
+			ADDS(hbuf); ADDS("/sec");
+			break;
+		case 'i':
+			(void)snprintf(nbuf, sizeof(nbuf), "%llu",
+			    (unsigned long long)st.in_part);
+			ADDS(nbuf);
+			break;
+		case 'I':
+			(void)snprintf(nbuf, sizeof(nbuf), "%llu",
+			    (unsigned long long)st.in_full);
+			ADDS(nbuf);
+			break;
+		case 'o':
+			(void)snprintf(nbuf, sizeof(nbuf), "%llu",
+			    (unsigned long long)st.out_part);
+			ADDS(nbuf);
+			break;
+		case 'O':
+			(void)snprintf(nbuf, sizeof(nbuf), "%llu",
+			    (unsigned long long)st.out_full);
+			ADDS(nbuf);
+			break;
+		case 's':
+			(void)snprintf(nbuf, sizeof(nbuf), "%li.%03d",
+			    (long) (mS / 1000), (int) (mS % 1000));
+			ADDS(nbuf);
+			break;
+		case 'p':
+			(void)snprintf(nbuf, sizeof(nbuf), "%llu",
+			    (unsigned long long)st.sparse);
+			ADDS(nbuf);
+			break;
+		case 't':
+			(void)snprintf(nbuf, sizeof(nbuf), "%llu",
+			    (unsigned long long)st.trunc);
+			ADDS(nbuf);
+			break;
+		case 'w':
+			(void)snprintf(nbuf, sizeof(nbuf), "%llu",
+			    (unsigned long long)st.swab);
+			ADDS(nbuf);
+			break;
+		case 'P':
+			ADDS("block");
+			if (st.sparse != 1) ADDS("s");
+			break;
+		case 'T':
+			ADDS("block");
+			if (st.trunc != 1) ADDS("s");
+			break;
+		case 'W':
+			ADDS("block");
+			if (st.swab != 1) ADDS("s");
+			break;
+		case '%':
+			ADDC(*ptr);
+			break;
+		default:
+			if (*ptr == '\0')
+				goto done;
+			errx(EXIT_FAILURE, "unknown specifier '%c' in "
+			    "msgfmt string", *ptr);
+			/* NOTREACHED */
+		}
+	}
+
+done:
+	/* flush buffer */
+	buffer_write(NULL, 0, 1);
+	return 0;
+}
+
+static void
+custom_summary(void)
+{
+
+	dd_write_msg(msgfmt, 1);
+}
+
+static void
+human_summary(void)
+{
+	(void)dd_write_msg("%I+%i records in\n%O+%o records out\n", 1);
+	if (st.swab) {
+		(void)dd_write_msg("%w odd length swab %W\n", 1);
+	}
+	if (st.trunc) {
+		(void)dd_write_msg("%t truncated %T\n", 1);
+	}
+	if (st.sparse) {
+		(void)dd_write_msg("%p sparse output %P\n", 1);
+	}
+	(void)dd_write_msg("%b bytes (%B) transferred in %s secs "
+	    "(%e bytes/sec - %E)\n", 1);
+}
+
+static void
+quiet_summary(void)
+{
+
+	/* stay quiet */
+}
+#endif /* NO_MSGFMT */
diff --git a/toolbox/upstream-netbsd/bin/dd/position.c b/toolbox/upstream-netbsd/bin/dd/position.c
new file mode 100644
index 0000000..36dd580
--- /dev/null
+++ b/toolbox/upstream-netbsd/bin/dd/position.c
@@ -0,0 +1,185 @@
+/*	$NetBSD: position.c,v 1.18 2010/11/22 21:04:28 pooka Exp $	*/
+
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego and Lance
+ * Visser of Convex Computer Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)position.c	8.3 (Berkeley) 4/2/94";
+#else
+__RCSID("$NetBSD: position.c,v 1.18 2010/11/22 21:04:28 pooka Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mtio.h>
+#include <sys/time.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "dd.h"
+#include "extern.h"
+
+/*
+ * Position input/output data streams before starting the copy.  Device type
+ * dependent.  Seekable devices use lseek, and the rest position by reading.
+ * Seeking past the end of file can cause null blocks to be written to the
+ * output.
+ */
+void
+pos_in(void)
+{
+	int bcnt, cnt, nr, warned;
+
+	/* If not a pipe or tape device, try to seek on it. */
+	if (!(in.flags & (ISPIPE|ISTAPE))) {
+		if (ddop_lseek(in, in.fd,
+		    (off_t)in.offset * (off_t)in.dbsz, SEEK_CUR) == -1) {
+			err(EXIT_FAILURE, "%s", in.name);
+			/* NOTREACHED */
+		}
+		return;
+		/* NOTREACHED */
+	}
+
+	/*
+	 * Read the data.  If a pipe, read until satisfy the number of bytes
+	 * being skipped.  No differentiation for reading complete and partial
+	 * blocks for other devices.
+	 */
+	for (bcnt = in.dbsz, cnt = in.offset, warned = 0; cnt;) {
+		if ((nr = ddop_read(in, in.fd, in.db, bcnt)) > 0) {
+			if (in.flags & ISPIPE) {
+				if (!(bcnt -= nr)) {
+					bcnt = in.dbsz;
+					--cnt;
+				}
+			} else
+				--cnt;
+			continue;
+		}
+
+		if (nr == 0) {
+			if (files_cnt > 1) {
+				--files_cnt;
+				continue;
+			}
+			errx(EXIT_FAILURE, "skip reached end of input");
+			/* NOTREACHED */
+		}
+
+		/*
+		 * Input error -- either EOF with no more files, or I/O error.
+		 * If noerror not set die.  POSIX requires that the warning
+		 * message be followed by an I/O display.
+		 */
+		if (ddflags & C_NOERROR) {
+			if (!warned) {
+
+				warn("%s", in.name);
+				warned = 1;
+				summary();
+			}
+			continue;
+		}
+		err(EXIT_FAILURE, "%s", in.name);
+		/* NOTREACHED */
+	}
+}
+
+void
+pos_out(void)
+{
+	struct mtop t_op;
+	int n;
+	uint64_t cnt;
+
+	/*
+	 * If not a tape, try seeking on the file.  Seeking on a pipe is
+	 * going to fail, but don't protect the user -- they shouldn't
+	 * have specified the seek operand.
+	 */
+	if (!(out.flags & ISTAPE)) {
+		if (ddop_lseek(out, out.fd,
+		    (off_t)out.offset * (off_t)out.dbsz, SEEK_SET) == -1)
+			err(EXIT_FAILURE, "%s", out.name);
+			/* NOTREACHED */
+		return;
+	}
+
+	/* If no read access, try using mtio. */
+	if (out.flags & NOREAD) {
+		t_op.mt_op = MTFSR;
+		t_op.mt_count = out.offset;
+
+		if (ddop_ioctl(out, out.fd, MTIOCTOP, &t_op) < 0)
+			err(EXIT_FAILURE, "%s", out.name);
+			/* NOTREACHED */
+		return;
+	}
+
+	/* Read it. */
+	for (cnt = 0; cnt < out.offset; ++cnt) {
+		if ((n = ddop_read(out, out.fd, out.db, out.dbsz)) > 0)
+			continue;
+
+		if (n < 0)
+			err(EXIT_FAILURE, "%s", out.name);
+			/* NOTREACHED */
+
+		/*
+		 * If reach EOF, fill with NUL characters; first, back up over
+		 * the EOF mark.  Note, cnt has not yet been incremented, so
+		 * the EOF read does not count as a seek'd block.
+		 */
+		t_op.mt_op = MTBSR;
+		t_op.mt_count = 1;
+		if (ddop_ioctl(out, out.fd, MTIOCTOP, &t_op) == -1)
+			err(EXIT_FAILURE, "%s", out.name);
+			/* NOTREACHED */
+
+		while (cnt++ < out.offset)
+			if ((uint64_t)(n = bwrite(&out,
+			    out.db, out.dbsz)) != out.dbsz)
+				err(EXIT_FAILURE, "%s", out.name);
+				/* NOTREACHED */
+		break;
+	}
+}
diff --git a/toolbox/upstream-netbsd/bin/kill/kill.c b/toolbox/upstream-netbsd/bin/kill/kill.c
new file mode 100644
index 0000000..0592577
--- /dev/null
+++ b/toolbox/upstream-netbsd/bin/kill/kill.c
@@ -0,0 +1,253 @@
+/* $NetBSD: kill.c,v 1.27 2011/08/29 14:51:18 joerg Exp $ */
+
+/*
+ * Copyright (c) 1988, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#if !defined(lint) && !defined(SHELL)
+__COPYRIGHT("@(#) Copyright (c) 1988, 1993, 1994\
+ The Regents of the University of California.  All rights reserved.");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)kill.c	8.4 (Berkeley) 4/28/95";
+#else
+__RCSID("$NetBSD: kill.c,v 1.27 2011/08/29 14:51:18 joerg Exp $");
+#endif
+#endif /* not lint */
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <inttypes.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+#include <locale.h>
+#include <sys/ioctl.h>
+
+#ifdef SHELL            /* sh (aka ash) builtin */
+int killcmd(int, char *argv[]);
+#define main killcmd
+#include "../../bin/sh/bltin/bltin.h"
+#endif /* SHELL */ 
+
+__dead static void nosig(char *);
+static void printsignals(FILE *);
+static int signame_to_signum(char *);
+__dead static void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+	int errors;
+	intmax_t numsig, pid;
+	char *ep;
+
+	setprogname(argv[0]);
+	setlocale(LC_ALL, "");
+	if (argc < 2)
+		usage();
+
+	numsig = SIGTERM;
+
+	argc--, argv++;
+	if (strcmp(*argv, "-l") == 0) {
+		argc--, argv++;
+		if (argc > 1)
+			usage();
+		if (argc == 1) {
+			if (isdigit((unsigned char)**argv) == 0)
+				usage();
+			numsig = strtoimax(*argv, &ep, 10);
+			/* check for correctly parsed number */
+			if (*ep != '\0' || numsig == INTMAX_MIN || numsig == INTMAX_MAX) {
+				errx(EXIT_FAILURE, "illegal signal number: %s",
+						*argv);
+				/* NOTREACHED */
+			}
+			if (numsig >= 128)
+				numsig -= 128;
+			/* and whether it fits into signals range */
+			if (numsig <= 0 || numsig >= NSIG)
+				nosig(*argv);
+			printf("%s\n", sys_signame[(int) numsig]);
+			exit(0);
+		}
+		printsignals(stdout);
+		exit(0);
+	}
+
+	if (!strcmp(*argv, "-s")) {
+		argc--, argv++;
+		if (argc < 1) {
+			warnx("option requires an argument -- s");
+			usage();
+		}
+		if (strcmp(*argv, "0")) {
+			if ((numsig = signame_to_signum(*argv)) < 0)
+				nosig(*argv);
+		} else
+			numsig = 0;
+		argc--, argv++;
+	} else if (**argv == '-') {
+		char *sn = *argv + 1;
+		if (isalpha((unsigned char)*sn)) {
+			if ((numsig = signame_to_signum(sn)) < 0)
+				nosig(sn);
+		} else if (isdigit((unsigned char)*sn)) {
+			numsig = strtoimax(sn, &ep, 10);
+			/* check for correctly parsed number */
+			if (*ep || numsig == INTMAX_MIN || numsig == INTMAX_MAX ) {
+				errx(EXIT_FAILURE, "illegal signal number: %s",
+						sn);
+				/* NOTREACHED */
+			}
+			/* and whether it fits into signals range */
+			if (numsig < 0 || numsig >= NSIG)
+				nosig(sn);
+		} else
+			nosig(sn);
+		argc--, argv++;
+	}
+
+	if (argc == 0)
+		usage();
+
+	for (errors = 0; argc; argc--, argv++) {
+#ifdef SHELL
+		extern int getjobpgrp(const char *);
+		if (*argv[0] == '%') {
+			pid = getjobpgrp(*argv);
+			if (pid == 0) {
+				warnx("illegal job id: %s", *argv);
+				errors = 1;
+				continue;
+			}
+		} else 
+#endif
+		{
+			pid = strtoimax(*argv, &ep, 10);
+			/* make sure the pid is a number and fits into pid_t */
+			if (!**argv || *ep || pid == INTMAX_MIN ||
+				pid == INTMAX_MAX || pid != (pid_t) pid) {
+
+				warnx("illegal process id: %s", *argv);
+				errors = 1;
+				continue;
+			}
+		}
+		if (kill((pid_t) pid, (int) numsig) == -1) {
+			warn("%s", *argv);
+			errors = 1;
+		}
+#ifdef SHELL
+		/* Wakeup the process if it was suspended, so it can
+		   exit without an explicit 'fg'. */
+		if (numsig == SIGTERM || numsig == SIGHUP)
+			kill((pid_t) pid, SIGCONT);
+#endif
+	}
+
+	exit(errors);
+	/* NOTREACHED */
+}
+
+static int
+signame_to_signum(char *sig)
+{
+	int n;
+
+	if (strncasecmp(sig, "sig", 3) == 0)
+		sig += 3;
+	for (n = 1; n < NSIG; n++) {
+		if (!strcasecmp(sys_signame[n], sig))
+			return (n);
+	}
+	return (-1);
+}
+
+static void
+nosig(char *name)
+{
+
+	warnx("unknown signal %s; valid signals:", name);
+	printsignals(stderr);
+	exit(1);
+	/* NOTREACHED */
+}
+
+static void
+printsignals(FILE *fp)
+{
+	int sig;
+	int len, nl;
+	const char *name;
+	int termwidth = 80;
+
+	if (isatty(fileno(fp))) {
+		struct winsize win;
+		if (ioctl(fileno(fp), TIOCGWINSZ, &win) == 0 && win.ws_col > 0)
+			termwidth = win.ws_col;
+	}
+
+	for (len = 0, sig = 1; sig < NSIG; sig++) {
+		name = sys_signame[sig];
+		nl = 1 + strlen(name);
+
+		if (len + nl >= termwidth) {
+			fprintf(fp, "\n");
+			len = 0;
+		} else
+			if (len != 0)
+				fprintf(fp, " ");
+		len += nl;
+		fprintf(fp, "%s", name);
+	}
+	if (len != 0)
+		fprintf(fp, "\n");
+}
+
+static void
+usage(void)
+{
+
+	fprintf(stderr, "usage: %s [-s signal_name] pid ...\n"
+	    "       %s -l [exit_status]\n"
+	    "       %s -signal_name pid ...\n"
+	    "       %s -signal_number pid ...\n",
+	    getprogname(), getprogname(), getprogname(), getprogname());
+	exit(1);
+	/* NOTREACHED */
+}
diff --git a/toolbox/upstream-netbsd/bin/ln/ln.c b/toolbox/upstream-netbsd/bin/ln/ln.c
new file mode 100644
index 0000000..9127477
--- /dev/null
+++ b/toolbox/upstream-netbsd/bin/ln/ln.c
@@ -0,0 +1,230 @@
+/* $NetBSD: ln.c,v 1.35 2011/08/29 14:38:30 joerg Exp $ */
+
+/*
+ * Copyright (c) 1987, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1987, 1993, 1994\
+ The Regents of the University of California.  All rights reserved.");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)ln.c	8.2 (Berkeley) 3/31/94";
+#else
+__RCSID("$NetBSD: ln.c,v 1.35 2011/08/29 14:38:30 joerg Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static int	fflag;				/* Unlink existing files. */
+static int	hflag;				/* Check new name for symlink first. */
+static int	iflag;				/* Interactive mode. */
+static int	sflag;				/* Symbolic, not hard, link. */
+static int	vflag;                          /* Verbose output */
+
+					/* System link call. */
+static int (*linkf)(const char *, const char *);
+static char   linkch;
+
+static int	linkit(const char *, const char *, int);
+__dead static void	usage(void);
+
+int
+main(int argc, char *argv[])
+{
+	struct stat sb;
+	int ch, exitval;
+	char *sourcedir;
+
+	setprogname(argv[0]);
+	(void)setlocale(LC_ALL, "");
+
+	while ((ch = getopt(argc, argv, "fhinsv")) != -1)
+		switch (ch) {
+		case 'f':
+			fflag = 1;
+			iflag = 0;
+			break;
+		case 'h':
+		case 'n':
+			hflag = 1;
+			break;
+		case 'i':
+			iflag = 1;
+			fflag = 0;
+			break;
+		case 's':
+			sflag = 1;
+			break;
+		case 'v':               
+			vflag = 1;
+			break;
+		case '?':
+		default:
+			usage();
+			/* NOTREACHED */
+		}
+
+	argv += optind;
+	argc -= optind;
+
+	if (sflag) {
+		linkf  = symlink;
+		linkch = '-';
+	} else {
+		linkf  = link;
+		linkch = '=';
+	}
+
+	switch(argc) {
+	case 0:
+		usage();
+		/* NOTREACHED */
+	case 1:				/* ln target */
+		exit(linkit(argv[0], ".", 1));
+		/* NOTREACHED */
+	case 2:				/* ln target source */
+		exit(linkit(argv[0], argv[1], 0));
+		/* NOTREACHED */
+	}
+
+					/* ln target1 target2 directory */
+	sourcedir = argv[argc - 1];
+	if (hflag && lstat(sourcedir, &sb) == 0 && S_ISLNK(sb.st_mode)) {
+		/* we were asked not to follow symlinks, but found one at
+		   the target--simulate "not a directory" error */
+		errno = ENOTDIR;
+		err(EXIT_FAILURE, "%s", sourcedir);
+		/* NOTREACHED */
+	}
+	if (stat(sourcedir, &sb)) {
+		err(EXIT_FAILURE, "%s", sourcedir);
+		/* NOTREACHED */
+	}
+	if (!S_ISDIR(sb.st_mode)) {
+		usage();
+		/* NOTREACHED */
+	}
+	for (exitval = 0; *argv != sourcedir; ++argv)
+		exitval |= linkit(*argv, sourcedir, 1);
+	exit(exitval);
+	/* NOTREACHED */
+}
+
+static int
+linkit(const char *target, const char *source, int isdir)
+{
+	struct stat sb;
+	const char *p;
+	char path[MAXPATHLEN];
+	int ch, exists, first;
+
+	if (!sflag) {
+		/* If target doesn't exist, quit now. */
+		if (stat(target, &sb)) {
+			warn("%s", target);
+			return (1);
+		}
+	}
+
+	/* If the source is a directory (and not a symlink if hflag),
+	   append the target's name. */
+	if (isdir ||
+	    (!lstat(source, &sb) && S_ISDIR(sb.st_mode)) ||
+	    (!hflag && !stat(source, &sb) && S_ISDIR(sb.st_mode))) {
+		if ((p = strrchr(target, '/')) == NULL)
+			p = target;
+		else
+			++p;
+		(void)snprintf(path, sizeof(path), "%s/%s", source, p);
+		source = path;
+	}
+
+	exists = !lstat(source, &sb);
+
+	/*
+	 * If the file exists, then unlink it forcibly if -f was specified
+	 * and interactively if -i was specified.
+	 */
+	if (fflag && exists) {
+		if (unlink(source)) {
+			warn("%s", source);
+			return (1);
+		}
+	} else if (iflag && exists) {
+		fflush(stdout);
+		(void)fprintf(stderr, "replace %s? ", source);
+
+		first = ch = getchar();
+		while (ch != '\n' && ch != EOF)
+			ch = getchar();
+		if (first != 'y' && first != 'Y') {
+			(void)fprintf(stderr, "not replaced\n");
+			return (1);
+		}
+
+		if (unlink(source)) {
+			warn("%s", source);
+			return (1);
+		}
+	}
+
+	/* Attempt the link. */
+	if ((*linkf)(target, source)) {
+		warn("%s", source);
+		return (1);
+	}
+	if (vflag)
+		(void)printf("%s %c> %s\n", source, linkch, target);
+
+	return (0);
+}
+
+static void
+usage(void)
+{
+
+	(void)fprintf(stderr,
+	    "usage:\t%s [-fhinsv] file1 file2\n\t%s [-fhinsv] file ... directory\n",
+	    getprogname(), getprogname());
+	exit(1);
+	/* NOTREACHED */
+}
diff --git a/toolbox/upstream-netbsd/bin/mv/mv.c b/toolbox/upstream-netbsd/bin/mv/mv.c
new file mode 100644
index 0000000..4be6c30
--- /dev/null
+++ b/toolbox/upstream-netbsd/bin/mv/mv.c
@@ -0,0 +1,396 @@
+/* $NetBSD: mv.c,v 1.43 2011/08/29 14:46:54 joerg Exp $ */
+
+/*
+ * Copyright (c) 1989, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ken Smith of The State University of New York at Buffalo.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1989, 1993, 1994\
+ The Regents of the University of California.  All rights reserved.");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)mv.c	8.2 (Berkeley) 4/2/94";
+#else
+__RCSID("$NetBSD: mv.c,v 1.43 2011/08/29 14:46:54 joerg Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/extattr.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <locale.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "pathnames.h"
+
+static int fflg, iflg, vflg;
+static int stdin_ok;
+
+static int	copy(char *, char *);
+static int	do_move(char *, char *);
+static int	fastcopy(char *, char *, struct stat *);
+__dead static void	usage(void);
+
+int
+main(int argc, char *argv[])
+{
+	int ch, len, rval;
+	char *p, *endp;
+	struct stat sb;
+	char path[MAXPATHLEN + 1];
+	size_t baselen;
+
+	setprogname(argv[0]);
+	(void)setlocale(LC_ALL, "");
+
+	while ((ch = getopt(argc, argv, "ifv")) != -1)
+		switch (ch) {
+		case 'i':
+			fflg = 0;
+			iflg = 1;
+			break;
+		case 'f':
+			iflg = 0;
+			fflg = 1;
+			break;
+		case 'v':
+			vflg = 1;
+			break;
+		default:
+			usage();
+		}
+	argc -= optind;
+	argv += optind;
+
+	if (argc < 2)
+		usage();
+
+	stdin_ok = isatty(STDIN_FILENO);
+
+	/*
+	 * If the stat on the target fails or the target isn't a directory,
+	 * try the move.  More than 2 arguments is an error in this case.
+	 */
+	if (stat(argv[argc - 1], &sb) || !S_ISDIR(sb.st_mode)) {
+		if (argc > 2)
+			usage();
+		exit(do_move(argv[0], argv[1]));
+	}
+
+	/* It's a directory, move each file into it. */
+	baselen = strlcpy(path, argv[argc - 1], sizeof(path));
+	if (baselen >= sizeof(path))
+		errx(1, "%s: destination pathname too long", argv[argc - 1]);
+	endp = &path[baselen];
+	if (!baselen || *(endp - 1) != '/') {
+		*endp++ = '/';
+		++baselen;
+	}
+	for (rval = 0; --argc; ++argv) {
+		p = *argv + strlen(*argv) - 1;
+		while (*p == '/' && p != *argv)
+			*p-- = '\0';
+		if ((p = strrchr(*argv, '/')) == NULL)
+			p = *argv;
+		else
+			++p;
+
+		if ((baselen + (len = strlen(p))) >= MAXPATHLEN) {
+			warnx("%s: destination pathname too long", *argv);
+			rval = 1;
+		} else {
+			memmove(endp, p, len + 1);
+			if (do_move(*argv, path))
+				rval = 1;
+		}
+	}
+	exit(rval);
+	/* NOTREACHED */
+}
+
+static int
+do_move(char *from, char *to)
+{
+	struct stat sb;
+	char modep[15];
+
+	/*
+	 * (1)	If the destination path exists, the -f option is not specified
+	 *	and either of the following conditions are true:
+	 *
+	 *	(a) The permissions of the destination path do not permit
+	 *	    writing and the standard input is a terminal.
+	 *	(b) The -i option is specified.
+	 *
+	 *	the mv utility shall write a prompt to standard error and
+	 *	read a line from standard input.  If the response is not
+	 *	affirmative, mv shall do nothing more with the current
+	 *	source file...
+	 */
+	if (!fflg && !access(to, F_OK)) {
+		int ask = 1;
+		int ch;
+
+		if (iflg) {
+			if (access(from, F_OK)) {
+				warn("rename %s", from);
+				return (1);
+			}
+			(void)fprintf(stderr, "overwrite %s? ", to);
+		} else if (stdin_ok && access(to, W_OK) && !stat(to, &sb)) {
+			if (access(from, F_OK)) {
+				warn("rename %s", from);
+				return (1);
+			}
+			strmode(sb.st_mode, modep);
+			(void)fprintf(stderr, "override %s%s%s/%s for %s? ",
+			    modep + 1, modep[9] == ' ' ? "" : " ",
+			    user_from_uid(sb.st_uid, 0),
+			    group_from_gid(sb.st_gid, 0), to);
+		} else
+			ask = 0;
+		if (ask) {
+			if ((ch = getchar()) != EOF && ch != '\n') {
+				int ch2;
+				while ((ch2 = getchar()) != EOF && ch2 != '\n')
+					continue;
+			}
+			if (ch != 'y' && ch != 'Y')
+				return (0);
+		}
+	}
+
+	/*
+	 * (2)	If rename() succeeds, mv shall do nothing more with the
+	 *	current source file.  If it fails for any other reason than
+	 *	EXDEV, mv shall write a diagnostic message to the standard
+	 *	error and do nothing more with the current source file.
+	 *
+	 * (3)	If the destination path exists, and it is a file of type
+	 *	directory and source_file is not a file of type directory,
+	 *	or it is a file not of type directory, and source file is
+	 *	a file of type directory, mv shall write a diagnostic
+	 *	message to standard error, and do nothing more with the
+	 *	current source file...
+	 */
+	if (!rename(from, to)) {
+		if (vflg)
+			printf("%s -> %s\n", from, to);
+		return (0);
+	}
+
+	if (errno != EXDEV) {
+		warn("rename %s to %s", from, to);
+		return (1);
+	}
+
+	/*
+	 * (4)	If the destination path exists, mv shall attempt to remove it.
+	 *	If this fails for any reason, mv shall write a diagnostic
+	 *	message to the standard error and do nothing more with the
+	 *	current source file...
+	 */
+	if (!lstat(to, &sb)) {
+		if ((S_ISDIR(sb.st_mode)) ? rmdir(to) : unlink(to)) {
+			warn("can't remove %s", to);
+			return (1);
+		}
+	}
+
+	/*
+	 * (5)	The file hierarchy rooted in source_file shall be duplicated
+	 *	as a file hierarchy rooted in the destination path...
+	 */
+	if (lstat(from, &sb)) {
+		warn("%s", from);
+		return (1);
+	}
+
+	return (S_ISREG(sb.st_mode) ?
+	    fastcopy(from, to, &sb) : copy(from, to));
+}
+
+static int
+fastcopy(char *from, char *to, struct stat *sbp)
+{
+	struct timeval tval[2];
+	static blksize_t blen;
+	static char *bp;
+	int nread, from_fd, to_fd;
+
+	if ((from_fd = open(from, O_RDONLY, 0)) < 0) {
+		warn("%s", from);
+		return (1);
+	}
+	if ((to_fd =
+	    open(to, O_CREAT | O_TRUNC | O_WRONLY, sbp->st_mode)) < 0) {
+		warn("%s", to);
+		(void)close(from_fd);
+		return (1);
+	}
+	if (!blen && !(bp = malloc(blen = sbp->st_blksize))) {
+		warn(NULL);
+		blen = 0;
+		(void)close(from_fd);
+		(void)close(to_fd);
+		return (1);
+	}
+	while ((nread = read(from_fd, bp, blen)) > 0)
+		if (write(to_fd, bp, nread) != nread) {
+			warn("%s", to);
+			goto err;
+		}
+	if (nread < 0) {
+		warn("%s", from);
+err:		if (unlink(to))
+			warn("%s: remove", to);
+		(void)close(from_fd);
+		(void)close(to_fd);
+		return (1);
+	}
+
+#ifndef __ANDROID__
+	if (fcpxattr(from_fd, to_fd) == -1)
+		warn("%s: error copying extended attributes", to);
+#endif
+
+	(void)close(from_fd);
+#ifdef BSD4_4
+	TIMESPEC_TO_TIMEVAL(&tval[0], &sbp->st_atimespec);
+	TIMESPEC_TO_TIMEVAL(&tval[1], &sbp->st_mtimespec);
+#else
+	tval[0].tv_sec = sbp->st_atime;
+	tval[1].tv_sec = sbp->st_mtime;
+	tval[0].tv_usec = 0;
+	tval[1].tv_usec = 0;
+#endif
+#ifdef __SVR4
+	if (utimes(to, tval))
+#else
+	if (futimes(to_fd, tval))
+#endif
+		warn("%s: set times", to);
+	if (fchown(to_fd, sbp->st_uid, sbp->st_gid)) {
+		if (errno != EPERM)
+			warn("%s: set owner/group", to);
+		sbp->st_mode &= ~(S_ISUID | S_ISGID);
+	}
+	if (fchmod(to_fd, sbp->st_mode))
+		warn("%s: set mode", to);
+#ifndef __ANDROID__
+	if (fchflags(to_fd, sbp->st_flags) && (errno != EOPNOTSUPP))
+		warn("%s: set flags (was: 0%07o)", to, sbp->st_flags);
+#endif
+
+	if (close(to_fd)) {
+		warn("%s", to);
+		return (1);
+	}
+
+	if (unlink(from)) {
+		warn("%s: remove", from);
+		return (1);
+	}
+
+	if (vflg)
+		printf("%s -> %s\n", from, to);
+
+	return (0);
+}
+
+static int
+copy(char *from, char *to)
+{
+	pid_t pid;
+	int status;
+
+	if ((pid = vfork()) == 0) {
+		execl(_PATH_CP, "mv", vflg ? "-PRpv" : "-PRp", "--", from, to, NULL);
+		warn("%s", _PATH_CP);
+		_exit(1);
+	}
+	if (waitpid(pid, &status, 0) == -1) {
+		warn("%s: waitpid", _PATH_CP);
+		return (1);
+	}
+	if (!WIFEXITED(status)) {
+		warnx("%s: did not terminate normally", _PATH_CP);
+		return (1);
+	}
+	if (WEXITSTATUS(status)) {
+		warnx("%s: terminated with %d (non-zero) status",
+		    _PATH_CP, WEXITSTATUS(status));
+		return (1);
+	}
+	if (!(pid = vfork())) {
+		execl(_PATH_RM, "mv", "-rf", "--", from, NULL);
+		warn("%s", _PATH_RM);
+		_exit(1);
+	}
+	if (waitpid(pid, &status, 0) == -1) {
+		warn("%s: waitpid", _PATH_RM);
+		return (1);
+	}
+	if (!WIFEXITED(status)) {
+		warnx("%s: did not terminate normally", _PATH_RM);
+		return (1);
+	}
+	if (WEXITSTATUS(status)) {
+		warnx("%s: terminated with %d (non-zero) status",
+		    _PATH_RM, WEXITSTATUS(status));
+		return (1);
+	}
+	return (0);
+}
+
+static void
+usage(void)
+{
+	(void)fprintf(stderr, "usage: %s [-fiv] source target\n"
+	    "       %s [-fiv] source ... directory\n", getprogname(),
+	    getprogname());
+	exit(1);
+	/* NOTREACHED */
+}
diff --git a/toolbox/cp/extern.h b/toolbox/upstream-netbsd/bin/mv/pathnames.h
similarity index 63%
copy from toolbox/cp/extern.h
copy to toolbox/upstream-netbsd/bin/mv/pathnames.h
index ffbadf7..7838946 100644
--- a/toolbox/cp/extern.h
+++ b/toolbox/upstream-netbsd/bin/mv/pathnames.h
@@ -1,7 +1,7 @@
-/* $NetBSD: extern.h,v 1.17 2012/01/04 15:58:37 christos Exp $ */
+/*	$NetBSD: pathnames.h,v 1.8 2004/08/19 22:26:07 christos Exp $	*/
 
-/*-
- * Copyright (c) 1991, 1993, 1994
+/*
+ * Copyright (c) 1989, 1993
  *	The Regents of the University of California.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -28,34 +28,18 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *	@(#)extern.h	8.2 (Berkeley) 4/1/94
+ *	@(#)pathnames.h	8.1 (Berkeley) 5/31/93
  */
 
-#ifndef _EXTERN_H_
-#define _EXTERN_H_
-
-typedef struct {
-	char *p_end;			/* pointer to NULL at end of path */
-	char *target_end;		/* pointer to end of target base */
-	char p_path[MAXPATHLEN + 1];	/* pointer to the start of a path */
-} PATH_T;
-
-extern PATH_T to;
-extern uid_t myuid;
-extern int Rflag, rflag, Hflag, Lflag, Pflag, fflag, iflag, lflag, pflag, Nflag;
-extern mode_t myumask;
-extern sig_atomic_t pinfo;
-
-#include <sys/cdefs.h>
-
-__BEGIN_DECLS
-int	copy_fifo(struct stat *, int);
-int	copy_file(FTSENT *, int);
-int	copy_link(FTSENT *, int);
-int	copy_special(struct stat *, int);
-int	set_utimes(const char *, struct stat *);
-int	setfile(struct stat *, int);
-void cp_usage(void) __attribute__((__noreturn__));
-__END_DECLS
-
-#endif /* !_EXTERN_H_ */
+#ifdef __ANDROID__
+#define	_PATH_RM	"/system/bin/rm"
+#define	_PATH_CP	"/system/bin/cp"
+#else
+#ifdef RESCUEDIR
+#define	_PATH_RM	RESCUEDIR "/rm"
+#define	_PATH_CP	RESCUEDIR "/cp"
+#else
+#define	_PATH_RM	"/bin/rm"
+#define	_PATH_CP	"/bin/cp"
+#endif
+#endif
diff --git a/toolbox/upstream-netbsd/bin/rm/rm.c b/toolbox/upstream-netbsd/bin/rm/rm.c
new file mode 100644
index 0000000..f183810
--- /dev/null
+++ b/toolbox/upstream-netbsd/bin/rm/rm.c
@@ -0,0 +1,625 @@
+/* $NetBSD: rm.c,v 1.53 2013/04/26 18:43:22 christos Exp $ */
+
+/*-
+ * Copyright (c) 1990, 1993, 1994, 2003
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1990, 1993, 1994\
+ The Regents of the University of California.  All rights reserved.");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)rm.c	8.8 (Berkeley) 4/27/95";
+#else
+__RCSID("$NetBSD: rm.c,v 1.53 2013/04/26 18:43:22 christos Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <fts.h>
+#include <grp.h>
+#include <locale.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static int dflag, eval, fflag, iflag, Pflag, stdin_ok, vflag, Wflag;
+static int xflag;
+static sig_atomic_t pinfo;
+
+static int	check(char *, char *, struct stat *);
+static void	checkdot(char **);
+static void	progress(int);
+static void	rm_file(char **);
+static int	rm_overwrite(char *, struct stat *);
+static void	rm_tree(char **);
+__dead static void	usage(void);
+
+/*
+ * For the sake of the `-f' flag, check whether an error number indicates the
+ * failure of an operation due to an non-existent file, either per se (ENOENT)
+ * or because its filename argument was illegal (ENAMETOOLONG, ENOTDIR).
+ */
+#define NONEXISTENT(x) \
+    ((x) == ENOENT || (x) == ENAMETOOLONG || (x) == ENOTDIR)
+
+/*
+ * rm --
+ *	This rm is different from historic rm's, but is expected to match
+ *	POSIX 1003.2 behavior.  The most visible difference is that -f
+ *	has two specific effects now, ignore non-existent files and force
+ * 	file removal.
+ */
+int
+main(int argc, char *argv[])
+{
+	int ch, rflag;
+
+	setprogname(argv[0]);
+	(void)setlocale(LC_ALL, "");
+
+	Pflag = rflag = xflag = 0;
+	while ((ch = getopt(argc, argv, "dfiPRrvWx")) != -1)
+		switch (ch) {
+		case 'd':
+			dflag = 1;
+			break;
+		case 'f':
+			fflag = 1;
+			iflag = 0;
+			break;
+		case 'i':
+			fflag = 0;
+			iflag = 1;
+			break;
+		case 'P':
+			Pflag = 1;
+			break;
+		case 'R':
+		case 'r':			/* Compatibility. */
+			rflag = 1;
+			break;
+		case 'v':
+			vflag = 1;
+			break;
+		case 'x':
+			xflag = 1;
+			break;
+#ifndef __ANDROID__
+		case 'W':
+			Wflag = 1;
+			break;
+#endif
+		case '?':
+		default:
+			usage();
+		}
+	argc -= optind;
+	argv += optind;
+
+	if (argc < 1) {
+		if (fflag)
+			return 0;
+		usage();
+	}
+
+	(void)signal(SIGINFO, progress);
+
+	checkdot(argv);
+
+	if (*argv) {
+		stdin_ok = isatty(STDIN_FILENO);
+
+		if (rflag)
+			rm_tree(argv);
+		else
+			rm_file(argv);
+	}
+
+	exit(eval);
+	/* NOTREACHED */
+}
+
+static void
+rm_tree(char **argv)
+{
+	FTS *fts;
+	FTSENT *p;
+	int flags, needstat, rval;
+			
+	/*
+	 * Remove a file hierarchy.  If forcing removal (-f), or interactive
+	 * (-i) or can't ask anyway (stdin_ok), don't stat the file.
+	 */
+	needstat = !fflag && !iflag && stdin_ok;
+
+	/*
+	 * If the -i option is specified, the user can skip on the pre-order
+	 * visit.  The fts_number field flags skipped directories.
+	 */
+#define	SKIPPED	1
+
+	flags = FTS_PHYSICAL;
+	if (!needstat)
+		flags |= FTS_NOSTAT;
+#ifndef __ANDROID__
+	if (Wflag)
+		flags |= FTS_WHITEOUT;
+#endif
+	if (xflag)
+		flags |= FTS_XDEV;
+	if ((fts = fts_open(argv, flags, NULL)) == NULL)
+		err(1, "fts_open failed");
+	while ((p = fts_read(fts)) != NULL) {
+	
+		switch (p->fts_info) {
+		case FTS_DNR:
+			if (!fflag || p->fts_errno != ENOENT) {
+				warnx("%s: %s", p->fts_path,
+						strerror(p->fts_errno));
+				eval = 1;
+			}
+			continue;
+		case FTS_ERR:
+			errx(EXIT_FAILURE, "%s: %s", p->fts_path,
+					strerror(p->fts_errno));
+			/* NOTREACHED */
+		case FTS_NS:
+			/*
+			 * FTS_NS: assume that if can't stat the file, it
+			 * can't be unlinked.
+			 */
+			if (fflag && NONEXISTENT(p->fts_errno))
+				continue;
+			if (needstat) {
+				warnx("%s: %s", p->fts_path,
+						strerror(p->fts_errno));
+				eval = 1;
+				continue;
+			}
+			break;
+		case FTS_D:
+			/* Pre-order: give user chance to skip. */
+			if (!fflag && !check(p->fts_path, p->fts_accpath,
+			    p->fts_statp)) {
+				(void)fts_set(fts, p, FTS_SKIP);
+				p->fts_number = SKIPPED;
+			}
+			continue;
+		case FTS_DP:
+			/* Post-order: see if user skipped. */
+			if (p->fts_number == SKIPPED)
+				continue;
+			break;
+		default:
+			if (!fflag &&
+			    !check(p->fts_path, p->fts_accpath, p->fts_statp))
+				continue;
+		}
+
+		rval = 0;
+		/*
+		 * If we can't read or search the directory, may still be
+		 * able to remove it.  Don't print out the un{read,search}able
+		 * message unless the remove fails.
+		 */
+		switch (p->fts_info) {
+		case FTS_DP:
+		case FTS_DNR:
+			rval = rmdir(p->fts_accpath);
+			if (rval != 0 && fflag && errno == ENOENT)
+				continue;
+			break;
+
+#ifndef __ANDROID__
+		case FTS_W:
+			rval = undelete(p->fts_accpath);
+			if (rval != 0 && fflag && errno == ENOENT)
+				continue;
+			break;
+#endif
+
+		default:
+			if (Pflag) {
+				if (rm_overwrite(p->fts_accpath, NULL))
+					continue;
+			}
+			rval = unlink(p->fts_accpath);
+			if (rval != 0 && fflag && NONEXISTENT(errno))
+				continue;
+			break;
+		}
+		if (rval != 0) {
+			warn("%s", p->fts_path);
+			eval = 1;
+		} else if (vflag || pinfo) {
+			pinfo = 0;
+			(void)printf("%s\n", p->fts_path);
+		}
+	}
+	if (errno)
+		err(1, "fts_read");
+	fts_close(fts);
+}
+
+static void
+rm_file(char **argv)
+{
+	struct stat sb;
+	int rval;
+	char *f;
+
+	/*
+	 * Remove a file.  POSIX 1003.2 states that, by default, attempting
+	 * to remove a directory is an error, so must always stat the file.
+	 */
+	while ((f = *argv++) != NULL) {
+		/* Assume if can't stat the file, can't unlink it. */
+		if (lstat(f, &sb)) {
+#ifndef __ANDROID__
+			if (Wflag) {
+				sb.st_mode = S_IFWHT|S_IWUSR|S_IRUSR;
+			} else {
+#endif
+				if (!fflag || !NONEXISTENT(errno)) {
+					warn("%s", f);
+					eval = 1;
+				}
+				continue;
+#ifndef __ANDROID__
+			}
+		} else if (Wflag) {
+			warnx("%s: %s", f, strerror(EEXIST));
+			eval = 1;
+			continue;
+#endif
+		}
+
+		if (S_ISDIR(sb.st_mode) && !dflag) {
+			warnx("%s: is a directory", f);
+			eval = 1;
+			continue;
+		}
+		if (!fflag && !S_ISWHT(sb.st_mode) && !check(f, f, &sb))
+			continue;
+#ifndef __ANDROID__
+		if (S_ISWHT(sb.st_mode))
+			rval = undelete(f);
+		else if (S_ISDIR(sb.st_mode))
+#else
+		if (S_ISDIR(sb.st_mode))
+#endif
+			rval = rmdir(f);
+		else {
+			if (Pflag) {
+				if (rm_overwrite(f, &sb))
+					continue;
+			}
+			rval = unlink(f);
+		}
+		if (rval && (!fflag || !NONEXISTENT(errno))) {
+			warn("%s", f);
+			eval = 1;
+		}
+		if (vflag && rval == 0)
+			(void)printf("%s\n", f);
+	}
+}
+
+/*
+ * rm_overwrite --
+ *	Overwrite the file 3 times with varying bit patterns.
+ *
+ * This is an expensive way to keep people from recovering files from your
+ * non-snapshotted FFS filesystems using fsdb(8).  Really.  No more.  Only
+ * regular files are deleted, directories (and therefore names) will remain.
+ * Also, this assumes a fixed-block file system (like FFS, or a V7 or a
+ * System V file system).  In a logging file system, you'll have to have
+ * kernel support.
+ *
+ * A note on standards:  U.S. DoD 5220.22-M "National Industrial Security
+ * Program Operating Manual" ("NISPOM") is often cited as a reference
+ * for clearing and sanitizing magnetic media.  In fact, a matrix of
+ * "clearing" and "sanitization" methods for various media was given in
+ * Chapter 8 of the original 1995 version of NISPOM.  However, that
+ * matrix was *removed from the document* when Chapter 8 was rewritten
+ * in Change 2 to the document in 2001.  Recently, the Defense Security
+ * Service has made a revised clearing and sanitization matrix available
+ * in Microsoft Word format on the DSS web site.  The standardization
+ * status of this matrix is unclear.  Furthermore, one must be very
+ * careful when referring to this matrix: it is intended for the "clearing"
+ * prior to reuse or "sanitization" prior to disposal of *entire media*,
+ * not individual files and the only non-physically-destructive method of
+ * "sanitization" that is permitted for magnetic disks of any kind is
+ * specifically noted to be prohibited for media that have contained
+ * Top Secret data.
+ *
+ * It is impossible to actually conform to the exact procedure given in
+ * the matrix if one is overwriting a file, not an entire disk, because
+ * the procedure requires examination and comparison of the disk's defect
+ * lists.  Any program that claims to securely erase *files* while 
+ * conforming to the standard, then, is not correct.  We do as much of
+ * what the standard requires as can actually be done when erasing a
+ * file, rather than an entire disk; but that does not make us conformant.
+ *
+ * Furthermore, the presence of track caches, disk and controller write
+ * caches, and so forth make it extremely difficult to ensure that data
+ * have actually been written to the disk, particularly when one tries
+ * to repeatedly overwrite the same sectors in quick succession.  We call
+ * fsync(), but controllers with nonvolatile cache, as well as IDE disks
+ * that just plain lie about the stable storage of data, will defeat this.
+ *
+ * Finally, widely respected research suggests that the given procedure
+ * is nowhere near sufficient to prevent the recovery of data using special
+ * forensic equipment and techniques that are well-known.  This is 
+ * presumably one reason that the matrix requires physical media destruction,
+ * rather than any technique of the sort attempted here, for secret data.
+ *
+ * Caveat Emptor.
+ *
+ * rm_overwrite will return 0 on success.
+ */
+
+static int
+rm_overwrite(char *file, struct stat *sbp)
+{
+	struct stat sb, sb2;
+	int fd, randint;
+	char randchar;
+
+	fd = -1;
+	if (sbp == NULL) {
+		if (lstat(file, &sb))
+			goto err;
+		sbp = &sb;
+	}
+	if (!S_ISREG(sbp->st_mode))
+		return 0;
+
+	/* flags to try to defeat hidden caching by forcing seeks */
+	if ((fd = open(file, O_RDWR|O_SYNC|O_RSYNC|O_NOFOLLOW, 0)) == -1)
+		goto err;
+
+	if (fstat(fd, &sb2)) {
+		goto err;
+	}
+
+	if (sb2.st_dev != sbp->st_dev || sb2.st_ino != sbp->st_ino ||
+	    !S_ISREG(sb2.st_mode)) {
+		errno = EPERM;
+		goto err;
+	}
+
+#define RAND_BYTES	1
+#define THIS_BYTE	0
+
+#define	WRITE_PASS(mode, byte) do {					\
+	off_t len;							\
+	size_t wlen, i;							\
+	char buf[8 * 1024];						\
+									\
+	if (fsync(fd) || lseek(fd, (off_t)0, SEEK_SET))			\
+		goto err;						\
+									\
+	if (mode == THIS_BYTE)						\
+		memset(buf, byte, sizeof(buf));				\
+	for (len = sbp->st_size; len > 0; len -= wlen) {		\
+		if (mode == RAND_BYTES) {				\
+			for (i = 0; i < sizeof(buf); 			\
+			    i+= sizeof(u_int32_t))			\
+				*(int *)(buf + i) = arc4random();	\
+		}							\
+		wlen = len < (off_t)sizeof(buf) ? (size_t)len : sizeof(buf); \
+		if ((size_t)write(fd, buf, wlen) != wlen)		\
+			goto err;					\
+	}								\
+	sync();		/* another poke at hidden caches */		\
+} while (/* CONSTCOND */ 0)
+
+#define READ_PASS(byte) do {						\
+	off_t len;							\
+	size_t rlen;							\
+	char pattern[8 * 1024];						\
+	char buf[8 * 1024];						\
+									\
+	if (fsync(fd) || lseek(fd, (off_t)0, SEEK_SET))			\
+		goto err;						\
+									\
+	memset(pattern, byte, sizeof(pattern));				\
+	for(len = sbp->st_size; len > 0; len -= rlen) {			\
+		rlen = len < (off_t)sizeof(buf) ? (size_t)len : sizeof(buf); \
+		if((size_t)read(fd, buf, rlen) != rlen)			\
+			goto err;					\
+		if(memcmp(buf, pattern, rlen))				\
+			goto err;					\
+	}								\
+	sync();		/* another poke at hidden caches */		\
+} while (/* CONSTCOND */ 0)
+
+	/*
+	 * DSS sanitization matrix "clear" for magnetic disks: 
+	 * option 'c' "Overwrite all addressable locations with a single 
+	 * character."
+	 */
+	randint = arc4random();
+	randchar = *(char *)&randint;
+	WRITE_PASS(THIS_BYTE, randchar);
+
+	/*
+	 * DSS sanitization matrix "sanitize" for magnetic disks: 
+	 * option 'd', sub 2 "Overwrite all addressable locations with a
+	 * character, then its complement.  Verify "complement" character
+	 * was written successfully to all addressable locations, then
+	 * overwrite all addressable locations with random characters; or
+	 * verify third overwrite of random characters."  The rest of the
+	 * text in d-sub-2 specifies requirements for overwriting spared
+	 * sectors; we cannot conform to it when erasing only a file, thus
+	 * we do not conform to the standard.
+	 */
+
+	/* 1. "a character" */
+	WRITE_PASS(THIS_BYTE, 0xff);
+
+	/* 2. "its complement" */
+	WRITE_PASS(THIS_BYTE, 0x00);
+
+	/* 3. "Verify 'complement' character" */
+	READ_PASS(0x00);
+
+	/* 4. "overwrite all addressable locations with random characters" */
+
+	WRITE_PASS(RAND_BYTES, 0x00);
+
+	/*
+	 * As the file might be huge, and we note that this revision of
+	 * the matrix says "random characters", not "a random character"
+	 * as the original did, we do not verify the random-character
+	 * write; the "or" in the standard allows this.
+	 */
+
+	if (close(fd) == -1) {
+		fd = -1;
+		goto err;
+	}
+
+	return 0;
+
+err:	eval = 1;
+	warn("%s", file);
+	if (fd != -1)
+		close(fd);
+	return 1;
+}
+
+static int
+check(char *path, char *name, struct stat *sp)
+{
+	int ch, first;
+	char modep[15];
+
+	/* Check -i first. */
+	if (iflag)
+		(void)fprintf(stderr, "remove '%s'? ", path);
+	else {
+		/*
+		 * If it's not a symbolic link and it's unwritable and we're
+		 * talking to a terminal, ask.  Symbolic links are excluded
+		 * because their permissions are meaningless.  Check stdin_ok
+		 * first because we may not have stat'ed the file.
+		 */
+		if (!stdin_ok || S_ISLNK(sp->st_mode) ||
+		    !(access(name, W_OK) && (errno != ETXTBSY)))
+			return (1);
+		strmode(sp->st_mode, modep);
+		if (Pflag) {
+			warnx(
+			    "%s: -P was specified but file could not"
+			    " be overwritten", path);
+			return 0;
+		}
+		(void)fprintf(stderr, "override %s%s%s:%s for '%s'? ",
+		    modep + 1, modep[9] == ' ' ? "" : " ",
+		    user_from_uid(sp->st_uid, 0),
+		    group_from_gid(sp->st_gid, 0), path);
+	}
+	(void)fflush(stderr);
+
+	first = ch = getchar();
+	while (ch != '\n' && ch != EOF)
+		ch = getchar();
+	return (first == 'y' || first == 'Y');
+}
+
+/*
+ * POSIX.2 requires that if "." or ".." are specified as the basename
+ * portion of an operand, a diagnostic message be written to standard
+ * error and nothing more be done with such operands.
+ *
+ * Since POSIX.2 defines basename as the final portion of a path after
+ * trailing slashes have been removed, we'll remove them here.
+ */
+#define ISDOT(a) ((a)[0] == '.' && (!(a)[1] || ((a)[1] == '.' && !(a)[2])))
+static void
+checkdot(char **argv)
+{
+	char *p, **save, **t;
+	int complained;
+
+	complained = 0;
+	for (t = argv; *t;) {
+		/* strip trailing slashes */
+		p = strrchr(*t, '\0');
+		while (--p > *t && *p == '/')
+			*p = '\0';
+
+		/* extract basename */
+		if ((p = strrchr(*t, '/')) != NULL)
+			++p;
+		else
+			p = *t;
+
+		if (ISDOT(p)) {
+			if (!complained++)
+				warnx("\".\" and \"..\" may not be removed");
+			eval = 1;
+			for (save = t; (t[0] = t[1]) != NULL; ++t)
+				continue;
+			t = save;
+		} else
+			++t;
+	}
+}
+
+static void
+usage(void)
+{
+
+	(void)fprintf(stderr, "usage: %s [-f|-i] [-dPRrvWx] file ...\n",
+	    getprogname());
+	exit(1);
+	/* NOTREACHED */
+}
+
+static void
+progress(int sig __unused)
+{
+	
+	pinfo++;
+}
diff --git a/toolbox/upstream-netbsd/bin/rmdir/rmdir.c b/toolbox/upstream-netbsd/bin/rmdir/rmdir.c
new file mode 100644
index 0000000..03261ce
--- /dev/null
+++ b/toolbox/upstream-netbsd/bin/rmdir/rmdir.c
@@ -0,0 +1,121 @@
+/* $NetBSD: rmdir.c,v 1.26 2011/08/29 14:49:38 joerg Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1992, 1993, 1994\
+ The Regents of the University of California.  All rights reserved.");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)rmdir.c	8.3 (Berkeley) 4/2/94";
+#else
+__RCSID("$NetBSD: rmdir.c,v 1.26 2011/08/29 14:49:38 joerg Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+
+#include <err.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static int	rm_path(char *);
+__dead static void	usage(void);
+
+int
+main(int argc, char *argv[])
+{
+	int ch, errors, pflag;
+
+	setprogname(argv[0]);
+	(void)setlocale(LC_ALL, "");
+
+	pflag = 0;
+	while ((ch = getopt(argc, argv, "p")) != -1)
+		switch(ch) {
+		case 'p':
+			pflag = 1;
+			break;
+		case '?':
+		default:
+			usage();
+		}
+	argc -= optind;
+	argv += optind;
+
+	if (argc == 0)
+		usage();
+
+	for (errors = 0; *argv; argv++) {
+		/* We rely on the kernel to ignore trailing '/' characters. */
+		if (rmdir(*argv) < 0) {
+			warn("%s", *argv);
+			errors = 1;
+		} else if (pflag)
+			errors |= rm_path(*argv);
+	}
+
+	exit(errors);
+	/* NOTREACHED */
+}
+
+static int
+rm_path(char *path)
+{
+	char *p;
+
+	while ((p = strrchr(path, '/')) != NULL) {
+		*p = 0;
+		if (p[1] == 0)
+			/* Ignore trailing '/' on deleted name */
+			continue;
+
+		if (rmdir(path) < 0) {
+			warn("%s", path);
+			return (1);
+		}
+	}
+
+	return (0);
+}
+
+static void
+usage(void)
+{
+	(void)fprintf(stderr, "usage: %s [-p] directory ...\n", getprogname());
+	exit(1);
+	/* NOTREACHED */
+}
diff --git a/toolbox/upstream-netbsd/bin/sleep/sleep.c b/toolbox/upstream-netbsd/bin/sleep/sleep.c
new file mode 100644
index 0000000..4349af4
--- /dev/null
+++ b/toolbox/upstream-netbsd/bin/sleep/sleep.c
@@ -0,0 +1,159 @@
+/* $NetBSD: sleep.c,v 1.24 2011/08/29 14:51:19 joerg Exp $ */
+
+/*
+ * Copyright (c) 1988, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1988, 1993, 1994\
+ The Regents of the University of California.  All rights reserved.");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)sleep.c	8.3 (Berkeley) 4/2/94";
+#else
+__RCSID("$NetBSD: sleep.c,v 1.24 2011/08/29 14:51:19 joerg Exp $");
+#endif
+#endif /* not lint */
+
+#include <ctype.h>
+#include <err.h>
+#include <locale.h>
+#include <math.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
+__dead static void alarmhandle(int);
+__dead static void usage(void);
+
+static volatile sig_atomic_t report_requested;
+static void
+report_request(int signo __unused)
+{
+
+	report_requested = 1;
+}
+
+int
+main(int argc, char *argv[])
+{
+	char *arg, *temp;
+	double fval, ival, val;
+	struct timespec ntime;
+	time_t original;
+	int ch, fracflag, rv;
+
+	setprogname(argv[0]);
+	(void)setlocale(LC_ALL, "");
+
+	(void)signal(SIGALRM, alarmhandle);
+
+	while ((ch = getopt(argc, argv, "")) != -1)
+		switch(ch) {
+		default:
+			usage();
+		}
+	argc -= optind;
+	argv += optind;
+
+	if (argc != 1)
+		usage();
+
+	/*
+	 * Okay, why not just use atof for everything? Why bother
+	 * checking if there is a fraction in use? Because the old
+	 * sleep handled the full range of integers, that's why, and a
+	 * double can't handle a large long. This is fairly useless
+	 * given how large a number a double can hold on most
+	 * machines, but now we won't ever have trouble. If you want
+	 * 1000000000.9 seconds of sleep, well, that's your
+	 * problem. Why use an isdigit() check instead of checking for
+	 * a period? Because doing it this way means locales will be
+	 * handled transparently by the atof code.
+	 */
+	fracflag = 0;
+	arg = *argv;
+	for (temp = arg; *temp != '\0'; temp++)
+		if (!isdigit((unsigned char)*temp))
+			fracflag++;
+
+	if (fracflag) {
+		val = atof(arg);
+		if (val <= 0)
+			usage();
+		ival = floor(val);
+		fval = (1000000000 * (val-ival));
+		ntime.tv_sec = ival;
+		ntime.tv_nsec = fval;
+	}
+	else {
+		ntime.tv_sec = atol(arg);
+		if (ntime.tv_sec <= 0)
+			return EXIT_SUCCESS;
+		ntime.tv_nsec = 0;
+	}
+
+	original = ntime.tv_sec;
+	signal(SIGINFO, report_request);
+	while ((rv = nanosleep(&ntime, &ntime)) != 0) {
+		if (report_requested) {
+		/* Reporting does not bother with nanoseconds. */
+			warnx("about %d second(s) left out of the original %d",
+			(int)ntime.tv_sec, (int)original);
+			report_requested = 0;
+		} else
+			break;
+	}
+
+	if (rv == -1)
+		err(EXIT_FAILURE, "nanosleep failed");
+
+	return EXIT_SUCCESS;
+	/* NOTREACHED */
+}
+
+static void
+usage(void)
+{
+	(void)fprintf(stderr, "usage: %s seconds\n", getprogname());
+	exit(EXIT_FAILURE);
+	/* NOTREACHED */
+}
+
+/* ARGSUSED */
+static void
+alarmhandle(int i)
+{
+	_exit(EXIT_SUCCESS);
+	/* NOTREACHED */
+}
diff --git a/toolbox/cp/extern.h b/toolbox/upstream-netbsd/bin/sync/sync.c
similarity index 64%
copy from toolbox/cp/extern.h
copy to toolbox/upstream-netbsd/bin/sync/sync.c
index ffbadf7..2b9c367 100644
--- a/toolbox/cp/extern.h
+++ b/toolbox/upstream-netbsd/bin/sync/sync.c
@@ -1,7 +1,7 @@
-/* $NetBSD: extern.h,v 1.17 2012/01/04 15:58:37 christos Exp $ */
+/* $NetBSD: sync.c,v 1.13 2008/07/20 00:52:40 lukem Exp $ */
 
-/*-
- * Copyright (c) 1991, 1993, 1994
+/*
+ * Copyright (c) 1987, 1993
  *	The Regents of the University of California.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -27,35 +27,33 @@
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
- *
- *	@(#)extern.h	8.2 (Berkeley) 4/1/94
  */
 
-#ifndef _EXTERN_H_
-#define _EXTERN_H_
-
-typedef struct {
-	char *p_end;			/* pointer to NULL at end of path */
-	char *target_end;		/* pointer to end of target base */
-	char p_path[MAXPATHLEN + 1];	/* pointer to the start of a path */
-} PATH_T;
-
-extern PATH_T to;
-extern uid_t myuid;
-extern int Rflag, rflag, Hflag, Lflag, Pflag, fflag, iflag, lflag, pflag, Nflag;
-extern mode_t myumask;
-extern sig_atomic_t pinfo;
-
 #include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1987, 1993\
+ The Regents of the University of California.  All rights reserved.");
+#endif /* not lint */
 
-__BEGIN_DECLS
-int	copy_fifo(struct stat *, int);
-int	copy_file(FTSENT *, int);
-int	copy_link(FTSENT *, int);
-int	copy_special(struct stat *, int);
-int	set_utimes(const char *, struct stat *);
-int	setfile(struct stat *, int);
-void cp_usage(void) __attribute__((__noreturn__));
-__END_DECLS
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)sync.c	8.1 (Berkeley) 5/31/93";
+#else
+__RCSID("$NetBSD: sync.c,v 1.13 2008/07/20 00:52:40 lukem Exp $");
+#endif
+#endif /* not lint */
 
-#endif /* !_EXTERN_H_ */
+#include <stdlib.h>
+#include <unistd.h>
+
+int main(int, char *[]);
+
+/* ARGSUSED */
+int
+main(int argc, char *argv[])
+{
+	setprogname(argv[0]);
+	sync();
+	exit(0);
+	/* NOTREACHED */
+}
diff --git a/toolbox/upstream-netbsd/include/namespace.h b/toolbox/upstream-netbsd/include/namespace.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/toolbox/upstream-netbsd/include/namespace.h
diff --git a/toolbox/upstream-netbsd/include/sys/extattr.h b/toolbox/upstream-netbsd/include/sys/extattr.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/toolbox/upstream-netbsd/include/sys/extattr.h
diff --git a/toolbox/upstream-netbsd/include/sys/mtio.h b/toolbox/upstream-netbsd/include/sys/mtio.h
new file mode 100644
index 0000000..8fb5655
--- /dev/null
+++ b/toolbox/upstream-netbsd/include/sys/mtio.h
@@ -0,0 +1 @@
+#include <linux/mtio.h>
diff --git a/toolbox/upstream-netbsd/lib/libc/gen/getbsize.c b/toolbox/upstream-netbsd/lib/libc/gen/getbsize.c
new file mode 100644
index 0000000..a9ce2c1
--- /dev/null
+++ b/toolbox/upstream-netbsd/lib/libc/gen/getbsize.c
@@ -0,0 +1,118 @@
+/*	$NetBSD: getbsize.c,v 1.17 2012/06/25 22:32:43 abs Exp $	*/
+
+/*-
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)getbsize.c	8.1 (Berkeley) 6/4/93";
+#else
+__RCSID("$NetBSD: getbsize.c,v 1.17 2012/06/25 22:32:43 abs Exp $");
+#endif
+#endif /* not lint */
+
+#include "namespace.h"
+
+#include <assert.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef __weak_alias
+__weak_alias(getbsize,_getbsize)
+#endif
+
+char *
+getbsize(int *headerlenp, long *blocksizep)
+{
+	static char header[20];
+	long n, max, mul, blocksize;
+	char *ep, *p;
+	const char *form;
+
+#define	KB	(1024L)
+#define	MB	(1024L * 1024L)
+#define	GB	(1024L * 1024L * 1024L)
+#define	MAXB	GB		/* No tera, peta, nor exa. */
+	form = "";
+	if ((p = getenv("BLOCKSIZE")) != NULL && *p != '\0') {
+		if ((n = strtol(p, &ep, 10)) < 0)
+			goto underflow;
+		if (n == 0)
+			n = 1;
+		if (*ep && ep[1])
+			goto fmterr;
+		switch (*ep) {
+		case 'G': case 'g':
+			form = "G";
+			max = MAXB / GB;
+			mul = GB;
+			break;
+		case 'K': case 'k':
+			form = "K";
+			max = MAXB / KB;
+			mul = KB;
+			break;
+		case 'M': case 'm':
+			form = "M";
+			max = MAXB / MB;
+			mul = MB;
+			break;
+		case '\0':
+			max = MAXB;
+			mul = 1;
+			break;
+		default:
+fmterr:			warnx("%s: unknown blocksize", p);
+			n = 512;
+			mul = 1;
+			max = 0;
+			break;
+		}
+		if (n > max) {
+			warnx("maximum blocksize is %ldG", MAXB / GB);
+			n = max;
+		}
+		if ((blocksize = n * mul) < 512) {
+underflow:		warnx("%s: minimum blocksize is 512", p);
+			form = "";
+			blocksize = n = 512;
+		}
+	} else
+		blocksize = n = 512;
+
+	if (headerlenp)
+		*headerlenp =
+		    snprintf(header, sizeof(header), "%ld%s-blocks", n, form);
+	if (blocksizep)
+		*blocksizep = blocksize;
+	return (header);
+}
diff --git a/toolbox/upstream-netbsd/lib/libc/gen/humanize_number.c b/toolbox/upstream-netbsd/lib/libc/gen/humanize_number.c
new file mode 100644
index 0000000..533560f
--- /dev/null
+++ b/toolbox/upstream-netbsd/lib/libc/gen/humanize_number.c
@@ -0,0 +1,161 @@
+/*	$NetBSD: humanize_number.c,v 1.16 2012/03/17 20:01:14 christos Exp $	*/
+
+/*
+ * Copyright (c) 1997, 1998, 1999, 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center, by Luke Mewburn and by Tomas Svensson.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: humanize_number.c,v 1.16 2012/03/17 20:01:14 christos Exp $");
+#endif /* LIBC_SCCS and not lint */
+
+#include "namespace.h"
+#include <assert.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <locale.h>
+
+int
+humanize_number(char *buf, size_t len, int64_t bytes,
+    const char *suffix, int scale, int flags)
+{
+	const char *prefixes, *sep;
+	int	b, r, s1, s2, sign;
+	int64_t	divisor, max, post = 1;
+	size_t	i, baselen, maxscale;
+
+	_DIAGASSERT(buf != NULL);
+	_DIAGASSERT(suffix != NULL);
+	_DIAGASSERT(scale >= 0);
+
+	if (flags & HN_DIVISOR_1000) {
+		/* SI for decimal multiplies */
+		divisor = 1000;
+		if (flags & HN_B)
+			prefixes = "B\0k\0M\0G\0T\0P\0E";
+		else
+			prefixes = "\0\0k\0M\0G\0T\0P\0E";
+	} else {
+		/*
+		 * binary multiplies
+		 * XXX IEC 60027-2 recommends Ki, Mi, Gi...
+		 */
+		divisor = 1024;
+		if (flags & HN_B)
+			prefixes = "B\0K\0M\0G\0T\0P\0E";
+		else
+			prefixes = "\0\0K\0M\0G\0T\0P\0E";
+	}
+
+#define	SCALE2PREFIX(scale)	(&prefixes[(scale) << 1])
+	maxscale = 7;
+
+	if ((size_t)scale >= maxscale &&
+	    (scale & (HN_AUTOSCALE | HN_GETSCALE)) == 0)
+		return (-1);
+
+	if (buf == NULL || suffix == NULL)
+		return (-1);
+
+	if (len > 0)
+		buf[0] = '\0';
+	if (bytes < 0) {
+		sign = -1;
+		baselen = 3;		/* sign, digit, prefix */
+		if (-bytes < INT64_MAX / 100)
+			bytes *= -100;
+		else {
+			bytes = -bytes;
+			post = 100;
+			baselen += 2;
+		}
+	} else {
+		sign = 1;
+		baselen = 2;		/* digit, prefix */
+		if (bytes < INT64_MAX / 100)
+			bytes *= 100;
+		else {
+			post = 100;
+			baselen += 2;
+		}
+	}
+	if (flags & HN_NOSPACE)
+		sep = "";
+	else {
+		sep = " ";
+		baselen++;
+	}
+	baselen += strlen(suffix);
+
+	/* Check if enough room for `x y' + suffix + `\0' */
+	if (len < baselen + 1)
+		return (-1);
+
+	if (scale & (HN_AUTOSCALE | HN_GETSCALE)) {
+		/* See if there is additional columns can be used. */
+		for (max = 100, i = len - baselen; i-- > 0;)
+			max *= 10;
+
+		/*
+		 * Divide the number until it fits the given column.
+		 * If there will be an overflow by the rounding below,
+		 * divide once more.
+		 */
+		for (i = 0; bytes >= max - 50 && i < maxscale; i++)
+			bytes /= divisor;
+
+		if (scale & HN_GETSCALE) {
+			_DIAGASSERT(__type_fit(int, i));
+			return (int)i;
+		}
+	} else
+		for (i = 0; i < (size_t)scale && i < maxscale; i++)
+			bytes /= divisor;
+	bytes *= post;
+
+	/* If a value <= 9.9 after rounding and ... */
+	if (bytes < 995 && i > 0 && flags & HN_DECIMAL) {
+		/* baselen + \0 + .N */
+		if (len < baselen + 1 + 2)
+			return (-1);
+		b = ((int)bytes + 5) / 10;
+		s1 = b / 10;
+		s2 = b % 10;
+		r = snprintf(buf, len, "%d%s%d%s%s%s",
+		    sign * s1, localeconv()->decimal_point, s2,
+		    sep, SCALE2PREFIX(i), suffix);
+	} else
+		r = snprintf(buf, len, "%" PRId64 "%s%s%s",
+		    sign * ((bytes + 50) / 100),
+		    sep, SCALE2PREFIX(i), suffix);
+
+	return (r);
+}
diff --git a/toolbox/upstream-netbsd/lib/libc/stdlib/strsuftoll.c b/toolbox/upstream-netbsd/lib/libc/stdlib/strsuftoll.c
new file mode 100644
index 0000000..80fc52f
--- /dev/null
+++ b/toolbox/upstream-netbsd/lib/libc/stdlib/strsuftoll.c
@@ -0,0 +1,249 @@
+/*	$NetBSD: strsuftoll.c,v 1.9 2011/10/22 22:08:47 christos Exp $	*/
+/*-
+ * Copyright (c) 2001-2002,2004 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego and Lance
+ * Visser of Convex Computer Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
+#include <sys/cdefs.h>
+
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: strsuftoll.c,v 1.9 2011/10/22 22:08:47 christos Exp $");
+#endif /* LIBC_SCCS and not lint */
+
+#ifdef _LIBC
+#include "namespace.h"
+#endif
+
+#if !HAVE_STRSUFTOLL
+
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef _LIBC
+# ifdef __weak_alias
+__weak_alias(strsuftoll, _strsuftoll)
+__weak_alias(strsuftollx, _strsuftollx)
+# endif
+#endif /* LIBC */
+
+/*
+ * Convert an expression of the following forms to a (u)int64_t.
+ * 	1) A positive decimal number.
+ *	2) A positive decimal number followed by a b (mult by 512).
+ *	3) A positive decimal number followed by a k (mult by 1024).
+ *	4) A positive decimal number followed by a m (mult by 1048576).
+ *	5) A positive decimal number followed by a g (mult by 1073741824).
+ *	6) A positive decimal number followed by a t (mult by 1099511627776).
+ *	7) A positive decimal number followed by a w (mult by sizeof int)
+ *	8) Two or more positive decimal numbers (with/without k,b or w).
+ *	   separated by x (also * for backwards compatibility), specifying
+ *	   the product of the indicated values.
+ * Returns the result upon successful conversion, or exits with an
+ * appropriate error.
+ * 
+ */
+/* LONGLONG */
+long long
+strsuftoll(const char *desc, const char *val,
+    long long min, long long max)
+{
+	long long result;
+	char	errbuf[100];
+
+	result = strsuftollx(desc, val, min, max, errbuf, sizeof(errbuf));
+	if (*errbuf != '\0')
+		errx(EXIT_FAILURE, "%s", errbuf);
+	return result;
+}
+
+/*
+ * As strsuftoll(), but returns the error message into the provided buffer
+ * rather than exiting with it.
+ */
+/* LONGLONG */
+static long long
+__strsuftollx(const char *desc, const char *val,
+    long long min, long long max, char *ebuf, size_t ebuflen, size_t depth)
+{
+	long long num, t;
+	char	*expr;
+
+	_DIAGASSERT(desc != NULL);
+	_DIAGASSERT(val != NULL);
+	_DIAGASSERT(ebuf != NULL);
+
+	if (depth > 16) {
+		snprintf(ebuf, ebuflen, "%s: Recursion limit exceeded", desc);
+		return 0;
+	}
+
+	while (isspace((unsigned char)*val))	/* Skip leading space */
+		val++;
+
+	errno = 0;
+	num = strtoll(val, &expr, 10);
+	if (errno == ERANGE)
+		goto erange;			/* Overflow */
+
+	if (expr == val)			/* No digits */
+		goto badnum;
+
+	switch (*expr) {
+	case 'b':
+		t = num;
+		num *= 512;			/* 1 block */
+		if (t > num)
+			goto erange;
+		++expr;
+		break;
+	case 'k':
+		t = num;
+		num *= 1024;			/* 1 kibibyte */
+		if (t > num)
+			goto erange;
+		++expr;
+		break;
+	case 'm':
+		t = num;
+		num *= 1048576;			/* 1 mebibyte */
+		if (t > num)
+			goto erange;
+		++expr;
+		break;
+	case 'g':
+		t = num;
+		num *= 1073741824;		/* 1 gibibyte */
+		if (t > num)
+			goto erange;
+		++expr;
+		break;
+	case 't':
+		t = num;
+		num *= 1099511627776LL;		/* 1 tebibyte */
+		if (t > num)
+			goto erange;
+		++expr;
+		break;
+	case 'w':
+		t = num;
+		num *= sizeof(int);		/* 1 word */
+		if (t > num)
+			goto erange;
+		++expr;
+		break;
+	}
+
+	switch (*expr) {
+	case '\0':
+		break;
+	case '*':				/* Backward compatible */
+	case 'x':
+		t = num;
+		num *= __strsuftollx(desc, expr + 1, min, max, ebuf, ebuflen,
+			depth + 1);
+		if (*ebuf != '\0')
+			return 0;
+		if (t > num) {
+ erange:	 	
+			errno = ERANGE;
+			snprintf(ebuf, ebuflen, "%s: %s", desc, strerror(errno));
+			return 0;
+		}
+		break;
+	default:
+ badnum:
+		snprintf(ebuf, ebuflen, "%s `%s': illegal number", desc, val);
+		return 0;
+	}
+	if (num < min) {
+		/* LONGLONG */
+		snprintf(ebuf, ebuflen, "%s %lld is less than %lld.",
+		    desc, (long long)num, (long long)min);
+		return 0;
+	}
+	if (num > max) {
+		/* LONGLONG */
+		snprintf(ebuf, ebuflen, "%s %lld is greater than %lld.",
+		    desc, (long long)num, (long long)max);
+		return 0;
+	}
+	*ebuf = '\0';
+	return num;
+}
+
+long long
+strsuftollx(const char *desc, const char *val,
+    long long min, long long max, char *ebuf, size_t ebuflen)
+{
+	return __strsuftollx(desc, val, min, max, ebuf, ebuflen, 0);
+}
+#endif /* !HAVE_STRSUFTOLL */
diff --git a/toolbox/cp/extern.h b/toolbox/upstream-netbsd/lib/libc/string/swab.c
similarity index 61%
copy from toolbox/cp/extern.h
copy to toolbox/upstream-netbsd/lib/libc/string/swab.c
index ffbadf7..392b186 100644
--- a/toolbox/cp/extern.h
+++ b/toolbox/upstream-netbsd/lib/libc/string/swab.c
@@ -1,9 +1,12 @@
-/* $NetBSD: extern.h,v 1.17 2012/01/04 15:58:37 christos Exp $ */
+/*	$NetBSD: swab.c,v 1.18 2011/01/04 17:14:07 martin Exp $	*/
 
-/*-
- * Copyright (c) 1991, 1993, 1994
+/*
+ * Copyright (c) 1988, 1993
  *	The Regents of the University of California.  All rights reserved.
  *
+ * This code is derived from software contributed to Berkeley by
+ * Jeffrey Mogul.
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -27,35 +30,51 @@
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
- *
- *	@(#)extern.h	8.2 (Berkeley) 4/1/94
  */
 
-#ifndef _EXTERN_H_
-#define _EXTERN_H_
-
-typedef struct {
-	char *p_end;			/* pointer to NULL at end of path */
-	char *target_end;		/* pointer to end of target base */
-	char p_path[MAXPATHLEN + 1];	/* pointer to the start of a path */
-} PATH_T;
-
-extern PATH_T to;
-extern uid_t myuid;
-extern int Rflag, rflag, Hflag, Lflag, Pflag, fflag, iflag, lflag, pflag, Nflag;
-extern mode_t myumask;
-extern sig_atomic_t pinfo;
-
 #include <sys/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char sccsid[] = "@(#)swab.c	8.1 (Berkeley) 6/4/93";
+#else
+__RCSID("$NetBSD: swab.c,v 1.18 2011/01/04 17:14:07 martin Exp $");
+#endif
+#endif /* LIBC_SCCS and not lint */
 
-__BEGIN_DECLS
-int	copy_fifo(struct stat *, int);
-int	copy_file(FTSENT *, int);
-int	copy_link(FTSENT *, int);
-int	copy_special(struct stat *, int);
-int	set_utimes(const char *, struct stat *);
-int	setfile(struct stat *, int);
-void cp_usage(void) __attribute__((__noreturn__));
-__END_DECLS
+#include <assert.h>
+#include <unistd.h>
 
-#endif /* !_EXTERN_H_ */
+void
+swab(const void * __restrict from, void * __restrict to, ssize_t len)
+{
+	char temp;
+	const char *fp;
+	char *tp;
+
+	if (len <= 1)
+		return;
+
+	_DIAGASSERT(from != NULL);
+	_DIAGASSERT(to != NULL);
+
+	len /= 2;
+	fp = (const char *)from;
+	tp = (char *)to;
+#define	STEP	temp = *fp++,*tp++ = *fp++,*tp++ = temp
+
+	if (__predict_false(len == 1)) {
+		STEP;
+		return;
+	}
+
+	/* round to multiple of 8 */
+	while ((--len % 8) != 0)
+		STEP;
+	len /= 8;
+	if (len == 0)
+		return;
+	while (len-- != 0) {
+		STEP; STEP; STEP; STEP;
+		STEP; STEP; STEP; STEP;
+	}
+}
diff --git a/toolbox/upstream-netbsd/lib/libutil/raise_default_signal.c b/toolbox/upstream-netbsd/lib/libutil/raise_default_signal.c
new file mode 100644
index 0000000..50cffd4
--- /dev/null
+++ b/toolbox/upstream-netbsd/lib/libutil/raise_default_signal.c
@@ -0,0 +1,117 @@
+/*	$NetBSD: raise_default_signal.c,v 1.3 2008/04/28 20:23:03 martin Exp $	 */
+
+/*-
+ * Copyright (c) 2007 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
+#include <sys/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: raise_default_signal.c,v 1.3 2008/04/28 20:23:03 martin Exp $");
+#endif
+
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <util.h>
+
+#if ! HAVE_RAISE_DEFAULT_SIGNAL
+/*
+ * raise_default_signal sig
+ *	Raise the default signal handler for sig, by
+ *	- block all signals
+ *	- set the signal handler to SIG_DFL
+ *	- raise the signal
+ *	- unblock the signal to deliver it
+ *
+ *	The original signal mask and signal handler is restored on exit
+ *	(whether successful or not).
+ *
+ *	Returns 0 on success, or -1 on failure with errno set to
+ *	on of the values for sigemptyset(), sigaddset(), sigprocmask(),
+ *	sigaction(), or raise().
+ */
+int
+raise_default_signal(int sig)
+{
+	struct sigaction origact, act;
+	sigset_t origmask, fullmask, mask;
+	int retval, oerrno;
+
+	retval = -1;
+
+		/* Setup data structures */
+		/* XXX memset(3) isn't async-safe according to signal(7) */
+	(void)memset(&act, 0, sizeof(act));
+	act.sa_handler = SIG_DFL;
+	act.sa_flags = 0;
+	if ((sigemptyset(&act.sa_mask) == -1) ||
+	    (sigfillset(&fullmask) == -1) ||
+	    (sigemptyset(&mask) == -1) ||
+	    (sigaddset(&mask, sig) == -1))
+		goto restore_none;
+
+		/* Block all signals */
+	if (sigprocmask(SIG_BLOCK, &fullmask, &origmask) == -1)
+		goto restore_none;
+		/* (use 'goto restore_mask' to restore state) */
+
+		/* Enable the SIG_DFL handler */
+	if (sigaction(sig, &act, &origact) == -1)
+		goto restore_mask;
+		/* (use 'goto restore_act' to restore state) */
+
+		/* Raise the signal, and unblock the signal to deliver it */
+	if ((raise(sig) == -1) ||
+	    (sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1))
+		goto restore_act;
+
+		/* Flag successful raise() */
+	retval = 0;
+
+		/* Restore the original handler */
+ restore_act:
+	oerrno = errno;
+	(void)sigaction(sig, &origact, NULL);
+	errno = oerrno;
+
+		/* Restore the original mask */
+ restore_mask:
+	oerrno = errno;
+	(void)sigprocmask(SIG_SETMASK, &origmask, NULL);
+	errno = oerrno;
+
+ restore_none:
+	return retval;
+}
+
+#endif	/* ! HAVE_RAISE_DEFAULT_SIGNAL */
diff --git a/toolbox/chown.c b/toolbox/upstream-netbsd/sbin/chown/chown.c
similarity index 99%
rename from toolbox/chown.c
rename to toolbox/upstream-netbsd/sbin/chown/chown.c
index 6ac2233..ee46eee 100644
--- a/toolbox/chown.c
+++ b/toolbox/upstream-netbsd/sbin/chown/chown.c
@@ -78,7 +78,7 @@
 };
 
 int
-chown_main(int argc, char **argv)
+main(int argc, char **argv)
 {
 	FTS *ftsp;
 	FTSENT *p;
diff --git a/toolbox/du.c b/toolbox/upstream-netbsd/usr.bin/du/du.c
similarity index 80%
rename from toolbox/du.c
rename to toolbox/upstream-netbsd/usr.bin/du/du.c
index c8beba5..086ac4a 100644
--- a/toolbox/du.c
+++ b/toolbox/upstream-netbsd/usr.bin/du/du.c
@@ -1,4 +1,4 @@
-/*	$NetBSD: du.c,v 1.33 2008/07/30 22:03:40 dsl Exp $	*/
+/*	$NetBSD: du.c,v 1.36 2012/03/11 11:23:20 shattered Exp $	*/
 
 /*
  * Copyright (c) 1989, 1993, 1994
@@ -42,10 +42,11 @@
 #if 0
 static char sccsid[] = "@(#)du.c	8.5 (Berkeley) 5/4/95";
 #else
-__RCSID("$NetBSD: du.c,v 1.33 2008/07/30 22:03:40 dsl Exp $");
+__RCSID("$NetBSD: du.c,v 1.36 2012/03/11 11:23:20 shattered Exp $");
 #endif
 #endif /* not lint */
 
+#include <sys/param.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 
@@ -53,6 +54,7 @@
 #include <err.h>
 #include <errno.h>
 #include <fts.h>
+#include <inttypes.h>
 #include <util.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -60,30 +62,32 @@
 #include <unistd.h>
 #include <limits.h>
 
-int	linkchk(dev_t, ino_t);
-void	prstat(const char *, int64_t);
-static void	usage(void);
+/* Count inodes or file size */
+#define	COUNT	(iflag ? 1 : p->fts_statp->st_blocks)
 
-long blocksize;
+static int	linkchk(dev_t, ino_t);
+static void	prstat(const char *, int64_t);
+__dead static void	usage(void);
 
-#define howmany(x, y)   (((x)+((y)-1))/(y))
+static int hflag, iflag;
+static long blocksize;
 
 int
-du_main(int argc, char *argv[])
+main(int argc, char *argv[])
 {
 	FTS *fts;
 	FTSENT *p;
 	int64_t totalblocks;
 	int ftsoptions, listfiles;
 	int depth;
-	int Hflag, Lflag, aflag, ch, cflag, dflag, gkmflag, rval, sflag;
+	int Hflag, Lflag, aflag, ch, cflag, dflag, gkmflag, nflag, rval, sflag;
 	const char *noargv[2];
 
-	Hflag = Lflag = aflag = cflag = dflag = gkmflag = sflag = 0;
+	Hflag = Lflag = aflag = cflag = dflag = gkmflag = nflag = sflag = 0;
 	totalblocks = 0;
 	ftsoptions = FTS_PHYSICAL;
 	depth = INT_MAX;
-	while ((ch = getopt(argc, argv, "HLPacd:ghkmnrsx")) != -1)
+	while ((ch = getopt(argc, argv, "HLPacd:ghikmnrsx")) != -1)
 		switch (ch) {
 		case 'H':
 			Hflag = 1;
@@ -115,6 +119,12 @@
 			blocksize = 1024 * 1024 * 1024;
 			gkmflag = 1;
 			break;
+		case 'h':
+			hflag = 1;
+			break;
+		case 'i':
+			iflag = 1;
+			break;
 		case 'k':
 			blocksize = 1024;
 			gkmflag = 1;
@@ -123,6 +133,9 @@
 			blocksize = 1024 * 1024;
 			gkmflag = 1;
 			break; 
+		case 'n':
+			nflag = 1;
+			break;
 		case 'r':
 			break;
 		case 's':
@@ -175,21 +188,36 @@
 	}
 
 	if (!gkmflag)
-		blocksize = 512;
+		(void)getbsize(NULL, &blocksize);
 	blocksize /= 512;
 
 	if ((fts = fts_open(argv, ftsoptions, NULL)) == NULL)
 		err(1, "fts_open `%s'", *argv);
 
 	for (rval = 0; (p = fts_read(fts)) != NULL;) {
+#ifndef __ANDROID__
+		if (nflag) {
+			switch (p->fts_info) {
+			case FTS_NS:
+			case FTS_SLNONE:
+				/* nothing */
+				break;
+			default:
+				if (p->fts_statp->st_flags & UF_NODUMP) {
+					fts_set(fts, p, FTS_SKIP);
+					continue;
+				}
+			}
+		}
+#endif
 		switch (p->fts_info) {
 		case FTS_D:			/* Ignore. */
 			break;
 		case FTS_DP:
 			p->fts_parent->fts_number += 
-			    p->fts_number += p->fts_statp->st_blocks;
+			    p->fts_number += COUNT;
 			if (cflag)
-				totalblocks += p->fts_statp->st_blocks;
+				totalblocks += COUNT;
 			/*
 			 * If listing each directory, or not listing files
 			 * or directories and this is post-order of the
@@ -216,10 +244,10 @@
 			 * the root of a traversal, display the total.
 			 */
 			if (listfiles || !p->fts_level)
-				prstat(p->fts_path, p->fts_statp->st_blocks);
-			p->fts_parent->fts_number += p->fts_statp->st_blocks;
+				prstat(p->fts_path, COUNT);
+			p->fts_parent->fts_number += COUNT;
 			if (cflag)
-				totalblocks += p->fts_statp->st_blocks;
+				totalblocks += COUNT;
 		}
 	}
 	if (errno)
@@ -229,15 +257,29 @@
 	exit(rval);
 }
 
-void
+static void
 prstat(const char *fname, int64_t blocks)
 {
-	(void)printf("%lld\t%s\n",
-	    (long long)howmany(blocks, (int64_t)blocksize),
-	    fname);
+	if (iflag) {
+		(void)printf("%" PRId64 "\t%s\n", blocks, fname);
+		return;
+	}
+
+	if (hflag) {
+		char buf[5];
+		int64_t sz = blocks * 512;
+
+		humanize_number(buf, sizeof(buf), sz, "", HN_AUTOSCALE,
+		    HN_B | HN_NOSPACE | HN_DECIMAL);
+
+		(void)printf("%s\t%s\n", buf, fname);
+	} else
+		(void)printf("%" PRId64 "\t%s\n",
+		    howmany(blocks, (int64_t)blocksize),
+		    fname);
 }
 
-int
+static int
 linkchk(dev_t dev, ino_t ino)
 {
 	static struct entry {
@@ -317,6 +359,6 @@
 {
 
 	(void)fprintf(stderr,
-		"usage: du [-H | -L | -P] [-a | -d depth | -s] [-cgkmrx] [file ...]\n");
+		"usage: du [-H | -L | -P] [-a | -d depth | -s] [-cghikmnrx] [file ...]\n");
 	exit(1);
 }
diff --git a/toolbox/grep/fastgrep.c b/toolbox/upstream-netbsd/usr.bin/grep/fastgrep.c
similarity index 100%
rename from toolbox/grep/fastgrep.c
rename to toolbox/upstream-netbsd/usr.bin/grep/fastgrep.c
diff --git a/toolbox/grep/file.c b/toolbox/upstream-netbsd/usr.bin/grep/file.c
similarity index 97%
rename from toolbox/grep/file.c
rename to toolbox/upstream-netbsd/usr.bin/grep/file.c
index d28dff5..da03d71 100644
--- a/toolbox/grep/file.c
+++ b/toolbox/upstream-netbsd/usr.bin/grep/file.c
@@ -41,7 +41,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 
-#ifndef ANDROID
+#ifndef __ANDROID__
 #include <bzlib.h>
 #endif
 #include <err.h>
@@ -53,7 +53,7 @@
 #include <unistd.h>
 #include <wchar.h>
 #include <wctype.h>
-#ifndef ANDROID
+#ifndef __ANDROID__
 #include <zlib.h>
 #endif
 
@@ -62,7 +62,7 @@
 #define	MAXBUFSIZ	(32 * 1024)
 #define	LNBUFBUMP	80
 
-#ifndef ANDROID
+#ifndef __ANDROID__
 static gzFile gzbufdesc;
 static BZFILE* bzbufdesc;
 #endif
@@ -78,14 +78,12 @@
 grep_refill(struct file *f)
 {
 	ssize_t nr;
-#ifndef ANDROID
 	int bzerr;
-#endif
 
 	bufpos = buffer;
 	bufrem = 0;
 
-#ifndef ANDROID
+#ifndef __ANDROID__
 	if (filebehave == FILE_GZIP)
 		nr = gzread(gzbufdesc, buffer, MAXBUFSIZ);
 	else if (filebehave == FILE_BZIP && bzbufdesc != NULL) {
@@ -204,7 +202,7 @@
 grep_file_init(struct file *f)
 {
 
-#ifndef ANDROID
+#ifndef __ANDROID__
 	if (filebehave == FILE_GZIP &&
 	    (gzbufdesc = gzdopen(f->fd, "r")) == NULL)
 		goto error;
diff --git a/toolbox/grep/grep.c b/toolbox/upstream-netbsd/usr.bin/grep/grep.c
similarity index 97%
rename from toolbox/grep/grep.c
rename to toolbox/upstream-netbsd/usr.bin/grep/grep.c
index 7b2c487..1ea6ed3 100644
--- a/toolbox/grep/grep.c
+++ b/toolbox/upstream-netbsd/usr.bin/grep/grep.c
@@ -1,4 +1,4 @@
-/*	$NetBSD: grep.c,v 1.11 2012/05/06 22:27:00 joerg Exp $	*/
+/*	$NetBSD: grep.c,v 1.12 2014/07/11 16:30:45 christos Exp $	*/
 /* 	$FreeBSD: head/usr.bin/grep/grep.c 211519 2010-08-19 22:55:17Z delphij $	*/
 /*	$OpenBSD: grep.c,v 1.42 2010/07/02 22:18:03 tedu Exp $	*/
 
@@ -34,7 +34,7 @@
 #endif
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: grep.c,v 1.11 2012/05/06 22:27:00 joerg Exp $");
+__RCSID("$NetBSD: grep.c,v 1.12 2014/07/11 16:30:45 christos Exp $");
 
 #include <sys/stat.h>
 #include <sys/types.h>
@@ -159,7 +159,6 @@
 {
 	fprintf(stderr, getstr(4), __progname);
 	fprintf(stderr, "%s", getstr(5));
-	fprintf(stderr, "%s", getstr(5));
 	fprintf(stderr, "%s", getstr(6));
 	fprintf(stderr, "%s", getstr(7));
 	exit(2);
@@ -312,7 +311,7 @@
 }
 
 int
-grep_main(int argc, char *argv[])
+main(int argc, char *argv[])
 {
 	char **aargv, **eargv, *eopts;
 	char *ep;
@@ -403,7 +402,7 @@
 				Aflag = 0;
 			else if (Aflag > LLONG_MAX / 10) {
 				errno = ERANGE;
-				err(2, "%llu", Aflag);
+				err(2, NULL);
 			}
 			Aflag = Bflag = (Aflag * 10) + (c - '0');
 			break;
@@ -420,10 +419,10 @@
 			l = strtoull(optarg, &ep, 10);
 			if (((errno == ERANGE) && (l == ULLONG_MAX)) ||
 			    ((errno == EINVAL) && (l == 0)))
-				err(2, "strtoull");
+				err(2, NULL);
 			else if (ep[0] != '\0') {
 				errno = EINVAL;
-				err(2, "empty");
+				err(2, NULL);
 			}
 			if (c == 'A')
 				Aflag = l;
@@ -509,10 +508,10 @@
 			mcount = strtoull(optarg, &ep, 10);
 			if (((errno == ERANGE) && (mcount == ULLONG_MAX)) ||
 			    ((errno == EINVAL) && (mcount == 0)))
-				err(2, "strtoull");
+				err(2, NULL);
 			else if (ep[0] != '\0') {
 				errno = EINVAL;
-				err(2, "empty");
+				err(2, NULL);
 			}
 			break;
 		case 'n':
diff --git a/toolbox/grep/grep.h b/toolbox/upstream-netbsd/usr.bin/grep/grep.h
similarity index 97%
rename from toolbox/grep/grep.h
rename to toolbox/upstream-netbsd/usr.bin/grep/grep.h
index 6454f93..fa2a3e3 100644
--- a/toolbox/grep/grep.h
+++ b/toolbox/upstream-netbsd/usr.bin/grep/grep.h
@@ -29,18 +29,14 @@
  * SUCH DAMAGE.
  */
 
-#ifdef ANDROID
-#define WITHOUT_NLS
-#endif
-
-#ifndef ANDROID
+#ifndef __ANDROID__
 #include <bzlib.h>
 #endif
 #include <limits.h>
 #include <regex.h>
 #include <stdbool.h>
 #include <stdio.h>
-#ifndef ANDROID
+#ifndef __ANDROID__
 #include <zlib.h>
 #endif
 
diff --git a/toolbox/grep/queue.c b/toolbox/upstream-netbsd/usr.bin/grep/queue.c
similarity index 100%
rename from toolbox/grep/queue.c
rename to toolbox/upstream-netbsd/usr.bin/grep/queue.c
diff --git a/toolbox/grep/util.c b/toolbox/upstream-netbsd/usr.bin/grep/util.c
similarity index 96%
rename from toolbox/grep/util.c
rename to toolbox/upstream-netbsd/usr.bin/grep/util.c
index 5712fee..ecd948d 100644
--- a/toolbox/grep/util.c
+++ b/toolbox/upstream-netbsd/usr.bin/grep/util.c
@@ -1,4 +1,4 @@
-/*	$NetBSD: util.c,v 1.16 2012/05/06 22:32:05 joerg Exp $	*/
+/*	$NetBSD: util.c,v 1.17 2013/01/21 03:24:43 msaitoh Exp $	*/
 /*	$FreeBSD: head/usr.bin/grep/util.c 211496 2010-08-19 09:28:59Z des $	*/
 /*	$OpenBSD: util.c,v 1.39 2010/07/02 22:18:03 tedu Exp $	*/
 
@@ -34,7 +34,7 @@
 #endif
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: util.c,v 1.16 2012/05/06 22:32:05 joerg Exp $");
+__RCSID("$NetBSD: util.c,v 1.17 2013/01/21 03:24:43 msaitoh Exp $");
 
 #include <sys/stat.h>
 #include <sys/types.h>
@@ -74,9 +74,10 @@
 	for (i = 0; i < fpatterns; ++i) {
 		if (fnmatch(fpattern[i].pat, fname, 0) == 0 ||
 		    fnmatch(fpattern[i].pat, fname_base, 0) == 0) {
-			if (fpattern[i].mode == EXCL_PAT)
+			if (fpattern[i].mode == EXCL_PAT) {
+				free(fname_copy);
 				return (false);
-			else
+			} else
 				ret = true;
 		}
 	}
@@ -128,7 +129,7 @@
 		break;
 	default:
 		fts_flags = FTS_LOGICAL;
-
+			
 	}
 
 	fts_flags |= FTS_NOSTAT | FTS_NOCHDIR;
@@ -273,7 +274,7 @@
 	return (c);
 }
 
-#define iswword(x)	(iswalnum((wint_t)(x)) || (x) == L'_')
+#define iswword(x)	(iswalnum((x)) || (x) == L'_')
 
 /*
  * Processes a line comparing it with the specified patterns.  Each pattern
@@ -474,13 +475,13 @@
 			if (!oflag)
 				fwrite(line->dat + a, matches[i].rm_so - a, 1,
 				    stdout);
-			if (color)
+			if (color) 
 				fprintf(stdout, "\33[%sm\33[K", color);
 
-				fwrite(line->dat + matches[i].rm_so,
+				fwrite(line->dat + matches[i].rm_so, 
 				    matches[i].rm_eo - matches[i].rm_so, 1,
 				    stdout);
-			if (color)
+			if (color) 
 				fprintf(stdout, "\33[m\33[K");
 			a = matches[i].rm_eo;
 			if (oflag)
diff --git a/toolbox/upstream-netbsd/usr.bin/printenv/printenv.c b/toolbox/upstream-netbsd/usr.bin/printenv/printenv.c
new file mode 100644
index 0000000..e15384f
--- /dev/null
+++ b/toolbox/upstream-netbsd/usr.bin/printenv/printenv.c
@@ -0,0 +1,102 @@
+/*	$NetBSD: printenv.c,v 1.12 2011/09/06 18:26:55 joerg Exp $	*/
+
+/*
+ * Copyright (c) 1987, 1993
+ *    The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1987, 1993\
+ The Regents of the University of California.  All rights reserved.");
+#endif /* not lint */
+
+#ifndef lint
+/*static char sccsid[] = "from: @(#)printenv.c	8.2 (Berkeley) 5/4/95";*/
+__RCSID("$NetBSD: printenv.c,v 1.12 2011/09/06 18:26:55 joerg Exp $");
+#endif /* not lint */
+
+#include <sys/types.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <err.h>
+
+__dead static void usage(void);
+
+/*
+ * printenv
+ *
+ * Bill Joy, UCB
+ * February, 1979
+ */
+int
+main(int argc, char *argv[])
+{
+	extern char **environ;
+	char *cp, **ep;
+	size_t len;
+	int ch;
+
+	while ((ch = getopt(argc, argv, "")) != -1)
+		switch(ch) {
+		case '?':
+		default:
+			usage();
+		}
+	argc -= optind;
+	argv += optind;
+
+	if (argc == 0) {
+		for (ep = environ; *ep; ep++)
+			(void)printf("%s\n", *ep);
+		exit(0);
+	}
+	if (argc != 1)
+		usage();
+	if (strchr(*argv, '=') != NULL)
+		errx(1, "Invalid environment variable %s", *argv);
+	len = strlen(*argv);
+	for (ep = environ; *ep; ep++)
+		if (!memcmp(*ep, *argv, len)) {
+			cp = *ep + len;
+			if (!*cp || *cp == '=') {
+				(void)printf("%s\n", *cp ? cp + 1 : cp);
+				exit(0);
+			}
+		}
+	exit(1);
+}
+
+static void
+usage(void)
+{
+	(void)fprintf(stderr, "Usage: printenv [name]\n");
+	exit(1);
+}