Merge "netcfg: Add MAC address to interface dump"
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk
index 752c953..6cfe79b 100644
--- a/debuggerd/Android.mk
+++ b/debuggerd/Android.mk
@@ -29,7 +29,7 @@
 LOCAL_SRC_FILES += $(TARGET_ARCH)/crashglue.S
 LOCAL_MODULE := crasher
 LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
-LOCAL_MODULE_TAGS := eng
+LOCAL_MODULE_TAGS := optional
 #LOCAL_FORCE_STATIC_EXECUTABLE := true
 LOCAL_SHARED_LIBRARIES := libcutils libc
 include $(BUILD_EXECUTABLE)
@@ -45,7 +45,7 @@
 LOCAL_SRC_FILES := vfp-crasher.c vfp.S
 LOCAL_MODULE := vfp-crasher
 LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
-LOCAL_MODULE_TAGS := eng
+LOCAL_MODULE_TAGS := optional
 LOCAL_SHARED_LIBRARIES := libcutils libc
 include $(BUILD_EXECUTABLE)
 endif # ARCH_ARM_HAVE_VFP == true
diff --git a/debuggerd/debuggerd.c b/debuggerd/debuggerd.c
index 5fa4442..7a3e781 100644
--- a/debuggerd/debuggerd.c
+++ b/debuggerd/debuggerd.c
@@ -642,7 +642,7 @@
         goto done;
     }
 
-    sprintf(buf,"/proc/%d/task/%d", cr.pid, tid);
+    snprintf(buf, sizeof buf, "/proc/%d/task/%d", cr.pid, tid);
     if(stat(buf, &s)) {
         LOG("tid %d does not exist in pid %d. ignoring debug request\n",
             tid, cr.pid);
@@ -652,7 +652,19 @@
 
     XLOG("BOOM: pid=%d uid=%d gid=%d tid=%d\n", cr.pid, cr.uid, cr.gid, tid);
 
+    /* Note that at this point, the target thread's signal handler
+     * is blocked in a read() call. This gives us the time to PTRACE_ATTACH
+     * to it before it has a chance to really fault.
+     *
+     * After the attach, the thread is stopped, and we write to the file
+     * descriptor to ensure that it will run as soon as we call PTRACE_CONT
+     * below. See details in bionic/libc/linker/debugger.c, in function
+     * debugger_signal_handler().
+     */
     tid_attach_status = ptrace(PTRACE_ATTACH, tid, 0, 0);
+
+    TEMP_FAILURE_RETRY(write(fd, &tid, 1));
+
     if(tid_attach_status < 0) {
         LOG("ptrace attach failed: %s\n", strerror(errno));
         goto done;
diff --git a/include/cutils/atomic-arm.h b/include/cutils/atomic-arm.h
index 004cc0c..16fe512 100644
--- a/include/cutils/atomic-arm.h
+++ b/include/cutils/atomic-arm.h
@@ -146,38 +146,6 @@
 
 
 #if defined(__thumb__)
-extern int32_t android_atomic_swap(int32_t new_value,
-                                   volatile int32_t *ptr);
-#elif defined(__ARM_HAVE_LDREX_STREX)
-extern inline int32_t android_atomic_swap(int32_t new_value,
-                                          volatile int32_t *ptr)
-{
-    int32_t prev, status;
-    do {
-        __asm__ __volatile__ ("ldrex %0, [%3]\n"
-                              "strex %1, %4, [%3]"
-                              : "=&r" (prev), "=&r" (status), "+m" (*ptr)
-                              : "r" (ptr), "r" (new_value)
-                              : "cc");
-    } while (__builtin_expect(status != 0, 0));
-    android_memory_barrier();
-    return prev;
-}
-#else
-extern inline int32_t android_atomic_swap(int32_t new_value,
-                                          volatile int32_t *ptr)
-{
-    int32_t prev;
-    __asm__ __volatile__ ("swp %0, %2, [%3]"
-                          : "=&r" (prev), "+m" (*ptr)
-                          : "r" (new_value), "r" (ptr)
-                          : "cc");
-    android_memory_barrier();
-    return prev;
-}
-#endif
-
-#if defined(__thumb__)
 extern int32_t android_atomic_add(int32_t increment,
                                   volatile int32_t *ptr);
 #elif defined(__ARM_HAVE_LDREX_STREX)
diff --git a/include/cutils/atomic-x86.h b/include/cutils/atomic-x86.h
index bce23ad..438012e 100644
--- a/include/cutils/atomic-x86.h
+++ b/include/cutils/atomic-x86.h
@@ -98,17 +98,6 @@
     return android_atomic_cas(old_value, new_value, ptr);
 }
 
-extern inline int32_t android_atomic_swap(int32_t new_value,
-                                          volatile int32_t *ptr)
-{
-    __asm__ __volatile__ ("xchgl %1, %0"
-                          : "=r" (new_value)
-                          : "m" (*ptr), "0" (new_value)
-                          : "memory");
-    /* new_value now holds the old value of *ptr */
-    return new_value;
-}
-
 extern inline int32_t android_atomic_add(int32_t increment,
                                          volatile int32_t *ptr)
 {
diff --git a/include/cutils/atomic.h b/include/cutils/atomic.h
index a50bf0f..ae42eb8 100644
--- a/include/cutils/atomic.h
+++ b/include/cutils/atomic.h
@@ -90,13 +90,6 @@
 void android_atomic_release_store(int32_t value, volatile int32_t* addr);
 
 /*
- * Unconditional swap operation with release ordering.
- *
- * Stores the new value at *addr, and returns the previous value.
- */
-int32_t android_atomic_swap(int32_t value, volatile int32_t* addr);
-
-/*
  * Compare-and-set operation with "acquire" or "release" ordering.
  *
  * This returns zero if the new value was successfully stored, which will
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index e446fc9..0f05a1b 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -53,7 +53,7 @@
 #define AID_KEYSTORE      1017  /* keystore subsystem */
 #define AID_USB           1018  /* USB devices */
 #define AID_DRM           1019  /* DRM server */
-#define AID_DRMIO         1020  /* DRM IO server */
+#define AID_AVAILABLE     1020  /* available for use */
 #define AID_GPS           1021  /* GPS daemon */
 #define AID_NFC           1022  /* nfc subsystem */
 #define AID_MEDIA_RW      1023  /* internal media storage write access */
@@ -100,7 +100,7 @@
     { "install",   AID_INSTALL, },
     { "media",     AID_MEDIA, },
     { "drm",       AID_DRM, },
-    { "drmio",     AID_DRMIO, },
+    { "available", AID_AVAILABLE, },
     { "nfc",       AID_NFC, },
     { "shell",     AID_SHELL, },
     { "cache",     AID_CACHE, },
diff --git a/include/sysutils/SocketListener.h b/include/sysutils/SocketListener.h
index c7edfeb..6592b01 100644
--- a/include/sysutils/SocketListener.h
+++ b/include/sysutils/SocketListener.h
@@ -30,7 +30,7 @@
     pthread_t               mThread;
 
 public:
-    SocketListener(const char *socketNames, bool listen);
+    SocketListener(const char *socketName, bool listen);
     SocketListener(int socketFd, bool listen);
 
     virtual ~SocketListener();
diff --git a/include/usbhost/usbhost.h b/include/usbhost/usbhost.h
index 7ef7ace..41e2ddc 100644
--- a/include/usbhost/usbhost.h
+++ b/include/usbhost/usbhost.h
@@ -177,6 +177,13 @@
 /* Releases the specified interface of a USB device */
 int usb_device_release_interface(struct usb_device *device, unsigned int interface);
 
+/* Requests the kernel to connect or disconnect its driver for the specified interface.
+ * This can be used to ask the kernel to disconnect its driver for a device
+ * so usb_device_claim_interface can claim it instead.
+ */
+int usb_device_connect_kernel_driver(struct usb_device *device,
+        unsigned int interface, int connect);
+
 /* Creates a new usb_request. */
 struct usb_request *usb_request_new(struct usb_device *dev,
         const struct usb_endpoint_descriptor *ep_desc);
diff --git a/init/builtins.c b/init/builtins.c
index 915c5aa..490ad48 100644
--- a/init/builtins.c
+++ b/init/builtins.c
@@ -485,6 +485,16 @@
     return symlink(args[1], args[2]);
 }
 
+int do_rm(int nargs, char **args)
+{
+    return unlink(args[1]);
+}
+
+int do_rmdir(int nargs, char **args)
+{
+    return rmdir(args[1]);
+}
+
 int do_sysclktz(int nargs, char **args)
 {
     struct timezone tz;
diff --git a/init/init_parser.c b/init/init_parser.c
index 00e6b9e..0898ae8 100644
--- a/init/init_parser.c
+++ b/init/init_parser.c
@@ -125,6 +125,8 @@
         break;
     case 'r':
         if (!strcmp(s, "estart")) return K_restart;
+        if (!strcmp(s, "mdir")) return K_rmdir;
+        if (!strcmp(s, "m")) return K_rm;
         break;
     case 's':
         if (!strcmp(s, "ervice")) return K_service;
diff --git a/init/keywords.h b/init/keywords.h
index d15ad49..c977fd7 100644
--- a/init/keywords.h
+++ b/init/keywords.h
@@ -15,6 +15,8 @@
 int do_mkdir(int nargs, char **args);
 int do_mount(int nargs, char **args);
 int do_restart(int nargs, char **args);
+int do_rm(int nargs, char **args);
+int do_rmdir(int nargs, char **args);
 int do_setkey(int nargs, char **args);
 int do_setprop(int nargs, char **args);
 int do_setrlimit(int nargs, char **args);
@@ -59,6 +61,8 @@
     KEYWORD(oneshot,     OPTION,  0, 0)
     KEYWORD(onrestart,   OPTION,  0, 0)
     KEYWORD(restart,     COMMAND, 1, do_restart)
+    KEYWORD(rm,          COMMAND, 1, do_rm)
+    KEYWORD(rmdir,       COMMAND, 1, do_rmdir)
     KEYWORD(service,     SECTION, 0, 0)
     KEYWORD(setenv,      OPTION,  2, 0)
     KEYWORD(setkey,      COMMAND, 0, do_setkey)
diff --git a/libcutils/atomic-android-sh.c b/libcutils/atomic-android-sh.c
index f8f1f57..8bac68a 100644
--- a/libcutils/atomic-android-sh.c
+++ b/libcutils/atomic-android-sh.c
@@ -113,18 +113,6 @@
     return oldValue;
 }
 
-int32_t android_atomic_acquire_swap(int32_t value, volatile int32_t* addr) {
-    return android_atomic_release_swap(value, addr);
-}
-
-int32_t android_atomic_release_swap(int32_t value, volatile int32_t* addr) {
-    int32_t oldValue;
-    do {
-        oldValue = *addr;
-    } while (android_atomic_cmpxchg(oldValue, value, addr));
-    return oldValue;
-}
-
 int android_atomic_acquire_cmpxchg(int32_t oldvalue, int32_t newvalue,
                            volatile int32_t* addr) {
     return android_atomic_release_cmpxchg(oldValue, newValue, addr);
diff --git a/libsysutils/Android.mk b/libsysutils/Android.mk
index dd2b32d..3b1f618 100644
--- a/libsysutils/Android.mk
+++ b/libsysutils/Android.mk
@@ -1,3 +1,4 @@
+ifneq ($(BUILD_TINY_ANDROID),true)
 BUILD_LIBSYSUTILS := false
 ifneq ($(TARGET_SIMULATOR),true)
     BUILD_LIBSYSUTILS := true
@@ -33,3 +34,4 @@
 include $(BUILD_SHARED_LIBRARY)
 
 endif
+endif
diff --git a/libsysutils/src/FrameworkClient.cpp b/libsysutils/src/FrameworkClient.cpp
index 562dd67..2f37055 100644
--- a/libsysutils/src/FrameworkClient.cpp
+++ b/libsysutils/src/FrameworkClient.cpp
@@ -14,13 +14,15 @@
 }
 
 int FrameworkClient::sendMsg(const char *msg) {
+    int ret;
     if (mSocket < 0) {
         errno = EHOSTUNREACH;
         return -1;
     }
 
     pthread_mutex_lock(&mWriteMutex);
-    if (write(mSocket, msg, strlen(msg) +1) < 0) {
+    ret = TEMP_FAILURE_RETRY(write(mSocket, msg, strlen(msg) +1));
+    if (ret < 0) {
         SLOGW("Unable to send msg '%s' (%s)", msg, strerror(errno));
     }
     pthread_mutex_unlock(&mWriteMutex);
@@ -28,13 +30,13 @@
 }
 
 int FrameworkClient::sendMsg(const char *msg, const char *data) {
-    char *buffer = (char *) alloca(strlen(msg) + strlen(data) + 1);
+    size_t bufflen = strlen(msg) + strlen(data) + 1;
+    char *buffer = (char *) alloca(bufflen);
     if (!buffer) {
         errno = -ENOMEM;
         return -1;
     }
-    strcpy(buffer, msg);
-    strcat(buffer, data);
+    snprintf(buffer, bufflen, "%s%s", msg, data);
     return sendMsg(buffer);
 }
 
diff --git a/libsysutils/src/FrameworkListener.cpp b/libsysutils/src/FrameworkListener.cpp
index 4da8eb6..3416ceb 100644
--- a/libsysutils/src/FrameworkListener.cpp
+++ b/libsysutils/src/FrameworkListener.cpp
@@ -34,7 +34,8 @@
     char buffer[255];
     int len;
 
-    if ((len = read(c->getSocket(), buffer, sizeof(buffer) -1)) < 0) {
+    len = TEMP_FAILURE_RETRY(read(c->getSocket(), buffer, sizeof(buffer)));
+    if (len < 0) {
         SLOGE("read() failed (%s)", strerror(errno));
         return false;
     } else if (!len)
@@ -45,6 +46,7 @@
 
     for (i = 0; i < len; i++) {
         if (buffer[i] == '\0') {
+            /* IMPORTANT: dispatchCommand() expects a zero-terminated string */
             dispatchCommand(c, buffer + offset);
             offset = i + 1;
         }
@@ -63,6 +65,7 @@
     char tmp[255];
     char *p = data;
     char *q = tmp;
+    char *qlimit = tmp + sizeof(tmp) - 1;
     bool esc = false;
     bool quote = false;
     int k;
@@ -72,6 +75,8 @@
     while(*p) {
         if (*p == '\\') {
             if (esc) {
+                if (q >= qlimit)
+                    goto overflow;
                 *q++ = '\\';
                 esc = false;
             } else
@@ -79,11 +84,15 @@
             p++;
             continue;
         } else if (esc) {
-            if (*p == '"')
+            if (*p == '"') {
+                if (q >= qlimit)
+                    goto overflow;
                 *q++ = '"';
-            else if (*p == '\\')
+            } else if (*p == '\\') {
+                if (q >= qlimit)
+                    goto overflow;
                 *q++ = '\\';
-            else {
+            } else {
                 cli->sendMsg(500, "Unsupported escape sequence", false);
                 goto out;
             }
@@ -101,9 +110,13 @@
             continue;
         }
 
+        if (q >= qlimit)
+            goto overflow;
         *q = *p++;
         if (!quote && *q == ' ') {
             *q = '\0';
+            if (argc >= CMD_ARGS_MAX)
+                goto overflow;
             argv[argc++] = strdup(tmp);
             memset(tmp, 0, sizeof(tmp));
             q = tmp;
@@ -112,6 +125,9 @@
         q++;
     }
 
+    *q = '\0';
+    if (argc >= CMD_ARGS_MAX)
+        goto overflow;
     argv[argc++] = strdup(tmp);
 #if 0
     for (k = 0; k < argc; k++) {
@@ -123,7 +139,7 @@
         cli->sendMsg(500, "Unclosed quotes error", false);
         goto out;
     }
-    
+
     for (i = mCommands->begin(); i != mCommands->end(); ++i) {
         FrameworkCommand *c = *i;
 
@@ -141,4 +157,8 @@
     for (j = 0; j < argc; j++)
         free(argv[j]);
     return;
+
+overflow:
+    cli->sendMsg(500, "Command too long", false);
+    goto out;
 }
diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp
index 86c1f42..c8d3b1f 100644
--- a/libsysutils/src/NetlinkEvent.cpp
+++ b/libsysutils/src/NetlinkEvent.cpp
@@ -56,45 +56,76 @@
     }
 }
 
+/* If the string between 'str' and 'end' begins with 'prefixlen' characters
+ * from the 'prefix' array, then return 'str + prefixlen', otherwise return
+ * NULL.
+ */
+static const char*
+has_prefix(const char* str, const char* end, const char* prefix, size_t prefixlen)
+{
+    if ((end-str) >= (ptrdiff_t)prefixlen && !memcmp(str, prefix, prefixlen))
+        return str + prefixlen;
+    else
+        return NULL;
+}
+
+/* Same as strlen(x) for constant string literals ONLY */
+#define CONST_STRLEN(x)  (sizeof(x)-1)
+
+/* Convenience macro to call has_prefix with a constant string literal  */
+#define HAS_CONST_PREFIX(str,end,prefix)  has_prefix((str),(end),prefix,CONST_STRLEN(prefix))
+
+
 bool NetlinkEvent::decode(char *buffer, int size) {
-    char *s = buffer;
-    char *end;
+    const char *s = buffer;
+    const char *end;
     int param_idx = 0;
     int i;
     int first = 1;
 
+    if (size == 0)
+        return false;
+
+    /* Ensure the buffer is zero-terminated, the code below depends on this */
+    buffer[size-1] = '\0';
+
     end = s + size;
     while (s < end) {
         if (first) {
-            char *p;
-            for (p = s; *p != '@'; p++);
-            p++;
-            mPath = strdup(p);
+            const char *p;
+            /* buffer is 0-terminated, no need to check p < end */
+            for (p = s; *p != '@'; p++) {
+                if (!*p) { /* no '@', should not happen */
+                    return false;
+                }
+            }
+            mPath = strdup(p+1);
             first = 0;
         } else {
-            if (!strncmp(s, "ACTION=", strlen("ACTION="))) {
-                char *a = s + strlen("ACTION=");
+            const char* a;
+            if ((a = HAS_CONST_PREFIX(s, end, "ACTION=")) != NULL) {
                 if (!strcmp(a, "add"))
                     mAction = NlActionAdd;
                 else if (!strcmp(a, "remove"))
                     mAction = NlActionRemove;
                 else if (!strcmp(a, "change"))
                     mAction = NlActionChange;
-            } else if (!strncmp(s, "SEQNUM=", strlen("SEQNUM=")))
-                mSeq = atoi(s + strlen("SEQNUM="));
-            else if (!strncmp(s, "SUBSYSTEM=", strlen("SUBSYSTEM=")))
-                mSubsystem = strdup(s + strlen("SUBSYSTEM="));
-            else
+            } else if ((a = HAS_CONST_PREFIX(s, end, "SEQNUM=")) != NULL) {
+                mSeq = atoi(a);
+            } else if ((a = HAS_CONST_PREFIX(s, end, "SUBSYSTEM=")) != NULL) {
+                mSubsystem = strdup(a);
+            } else if (param_idx < NL_PARAMS_MAX) {
                 mParams[param_idx++] = strdup(s);
+            }
         }
-        s+= strlen(s) + 1;
+        s += strlen(s) + 1;
     }
     return true;
 }
 
 const char *NetlinkEvent::findParam(const char *paramName) {
     size_t len = strlen(paramName);
-    for (int i = 0; mParams[i] && i < NL_PARAMS_MAX; ++i) {
+    for (int i = 0; i < NL_PARAMS_MAX && mParams[i] != NULL; ++i) {
         const char *ptr = mParams[i] + len;
         if (!strncmp(mParams[i], paramName, len) && *ptr == '=')
             return ++ptr;
diff --git a/libsysutils/src/NetlinkListener.cpp b/libsysutils/src/NetlinkListener.cpp
index e2a354e..a4f62c6 100644
--- a/libsysutils/src/NetlinkListener.cpp
+++ b/libsysutils/src/NetlinkListener.cpp
@@ -34,7 +34,8 @@
     int socket = cli->getSocket();
     int count;
 
-    if ((count = recv(socket, mBuffer, sizeof(mBuffer), 0)) < 0) {
+    count = TEMP_FAILURE_RETRY(recv(socket, mBuffer, sizeof(mBuffer), 0));
+    if (count < 0) {
         SLOGE("recv failed (%s)", strerror(errno));
         return false;
     }
diff --git a/libsysutils/src/ServiceManager.cpp b/libsysutils/src/ServiceManager.cpp
index 1ba6ef0..41ac1dd 100644
--- a/libsysutils/src/ServiceManager.cpp
+++ b/libsysutils/src/ServiceManager.cpp
@@ -10,7 +10,39 @@
 ServiceManager::ServiceManager() {
 }
 
+/* The service name should not exceed SERVICE_NAME_MAX to avoid
+ * some weird things. This is due to the fact that:
+ *
+ * - Starting a service is done by writing its name to the "ctl.start"
+ *   system property. This triggers the init daemon to actually start
+ *   the service for us.
+ *
+ * - Stopping the service is done by writing its name to "ctl.stop"
+ *   in a similar way.
+ *
+ * - Reading the status of a service is done by reading the property
+ *   named "init.svc.<name>"
+ *
+ * If strlen(<name>) > (PROPERTY_KEY_MAX-1)-9, then you can start/stop
+ * the service by writing to ctl.start/stop, but you won't be able to
+ * read its state due to the truncation of "init.svc.<name>" into a
+ * zero-terminated buffer of PROPERTY_KEY_MAX characters.
+ */
+#define SERVICE_NAME_MAX  (PROPERTY_KEY_MAX-10)
+
+/* The maximum amount of time to wait for a service to start or stop,
+ * in micro-seconds (really an approximation) */
+#define  SLEEP_MAX_USEC     2000000  /* 2 seconds */
+
+/* The minimal sleeping interval between checking for the service's state
+ * when looping for SLEEP_MAX_USEC */
+#define  SLEEP_MIN_USEC      200000  /* 200 msec */
+
 int ServiceManager::start(const char *name) {
+    if (strlen(name) > SERVICE_NAME_MAX) {
+        SLOGE("Service name '%s' is too long", name);
+        return 0;
+    }
     if (isRunning(name)) {
         SLOGW("Service '%s' is already running", name);
         return 0;
@@ -19,13 +51,14 @@
     SLOGD("Starting service '%s'", name);
     property_set("ctl.start", name);
 
-    int count = 200;
-    while(count--) {
-        sched_yield();
+    int count = SLEEP_MAX_USEC;
+    while(count > 0) {
+        usleep(SLEEP_MIN_USEC);
+        count -= SLEEP_MIN_USEC;
         if (isRunning(name))
             break;
     }
-    if (!count) {
+    if (count <= 0) {
         SLOGW("Timed out waiting for service '%s' to start", name);
         errno = ETIMEDOUT;
         return -1;
@@ -35,6 +68,10 @@
 }
 
 int ServiceManager::stop(const char *name) {
+    if (strlen(name) > SERVICE_NAME_MAX) {
+        SLOGE("Service name '%s' is too long", name);
+        return 0;
+    }
     if (!isRunning(name)) {
         SLOGW("Service '%s' is already stopped", name);
         return 0;
@@ -43,28 +80,33 @@
     SLOGD("Stopping service '%s'", name);
     property_set("ctl.stop", name);
 
-    int count = 200;
-    while(count--) {
-        sched_yield();
+    int count = SLEEP_MAX_USEC;
+    while(count > 0) {
+        usleep(SLEEP_MIN_USEC);
+        count -= SLEEP_MIN_USEC;
         if (!isRunning(name))
             break;
     }
 
-    if (!count) {
+    if (count <= 0) {
         SLOGW("Timed out waiting for service '%s' to stop", name);
         errno = ETIMEDOUT;
         return -1;
     }
-    SLOGD("Sucessfully stopped '%s'", name);
+    SLOGD("Successfully stopped '%s'", name);
     return 0;
 }
 
 bool ServiceManager::isRunning(const char *name) {
     char propVal[PROPERTY_VALUE_MAX];
-    char propName[255];
+    char propName[PROPERTY_KEY_MAX];
+    int  ret;
 
-    snprintf(propName, sizeof(propVal), "init.svc.%s", name);
-
+    ret = snprintf(propName, sizeof(propName), "init.svc.%s", name);
+    if (ret > (int)sizeof(propName)-1) {
+        SLOGD("Service name '%s' is too long", name);
+        return false;
+    }
 
     if (property_get(propName, propVal, NULL)) {
         if (!strcmp(propVal, "running"))
diff --git a/libsysutils/src/SocketClient.cpp b/libsysutils/src/SocketClient.cpp
index c9c7417..a6aed26 100644
--- a/libsysutils/src/SocketClient.cpp
+++ b/libsysutils/src/SocketClient.cpp
@@ -32,14 +32,24 @@
 
 int SocketClient::sendMsg(int code, const char *msg, bool addErrno) {
     char *buf;
+    const char* arg;
+    const char* fmt;
+    char tmp[1];
+    int  len;
 
     if (addErrno) {
-        buf = (char *) alloca(strlen(msg) + strlen(strerror(errno)) + 8);
-        sprintf(buf, "%.3d %s (%s)", code, msg, strerror(errno));
+        fmt = "%.3d %s (%s)";
+        arg = strerror(errno);
     } else {
-        buf = (char *) alloca(strlen(msg) + strlen("XXX "));
-        sprintf(buf, "%.3d %s", code, msg);
+        fmt = "%.3d %s";
+        arg = NULL;
     }
+    /* Measure length of required buffer */
+    len = snprintf(tmp, sizeof tmp, fmt, code, msg, arg);
+    /* Allocate in the stack, then write to it */
+    buf = (char*)alloca(len+1);
+    snprintf(buf, len+1, fmt, code, msg, arg);
+    /* Send the zero-terminated message */
     return sendMsg(buf);
 }
 
@@ -68,18 +78,24 @@
 
     pthread_mutex_lock(&mWriteMutex);
     while (brtw > 0) {
-        if ((rc = write(mSocket, p, brtw)) < 0) {
-            SLOGW("write error (%s)", strerror(errno));
-            pthread_mutex_unlock(&mWriteMutex);
-            return -1;
-        } else if (!rc) {
+        rc = write(mSocket, p, brtw);
+        if (rc > 0) {
+            p += rc;
+            brtw -= rc;
+            continue;
+        }
+
+        if (rc < 0 && errno == EINTR)
+            continue;
+
+        pthread_mutex_unlock(&mWriteMutex);
+        if (rc == 0) {
             SLOGW("0 length write :(");
             errno = EIO;
-            pthread_mutex_unlock(&mWriteMutex);
-            return -1;
+        } else {
+            SLOGW("write error (%s)", strerror(errno));
         }
-        p += rc;
-        brtw -= rc;
+        return -1;
     }
     pthread_mutex_unlock(&mWriteMutex);
     return 0;
diff --git a/libsysutils/src/SocketListener.cpp b/libsysutils/src/SocketListener.cpp
index 1bc06db..611d5fe 100644
--- a/libsysutils/src/SocketListener.cpp
+++ b/libsysutils/src/SocketListener.cpp
@@ -54,7 +54,7 @@
         close(mCtrlPipe[1]);
     }
     SocketClientCollection::iterator it;
-    for (it = mClients->begin(); it != mClients->end(); ++it) {
+    for (it = mClients->begin(); it != mClients->end();) {
         delete (*it);
         it = mClients->erase(it);
     }
@@ -96,8 +96,10 @@
 
 int SocketListener::stopListener() {
     char c = 0;
+    int  rc;
 
-    if (write(mCtrlPipe[1], &c, 1) != 1) {
+    rc = TEMP_FAILURE_RETRY(write(mCtrlPipe[1], &c, 1));
+    if (rc != 1) {
         SLOGE("Error writing to control pipe (%s)", strerror(errno));
         return -1;
     }
@@ -118,7 +120,7 @@
     }
 
     SocketClientCollection::iterator it;
-    for (it = mClients->begin(); it != mClients->end(); ++it) {
+    for (it = mClients->begin(); it != mClients->end();) {
         delete (*it);
         it = mClients->erase(it);
     }
@@ -135,11 +137,13 @@
 
 void SocketListener::runListener() {
 
+    SocketClientCollection *pendingList = new SocketClientCollection();
+
     while(1) {
         SocketClientCollection::iterator it;
         fd_set read_fds;
         int rc = 0;
-        int max = 0;
+        int max = -1;
 
         FD_ZERO(&read_fds);
 
@@ -154,13 +158,16 @@
 
         pthread_mutex_lock(&mClientsLock);
         for (it = mClients->begin(); it != mClients->end(); ++it) {
-            FD_SET((*it)->getSocket(), &read_fds);
-            if ((*it)->getSocket() > max)
-                max = (*it)->getSocket();
+            int fd = (*it)->getSocket();
+            FD_SET(fd, &read_fds);
+            if (fd > max)
+                max = fd;
         }
         pthread_mutex_unlock(&mClientsLock);
 
         if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) {
+            if (errno == EINTR)
+                continue;
             SLOGE("select failed (%s)", strerror(errno));
             sleep(1);
             continue;
@@ -171,10 +178,14 @@
             break;
         if (mListen && FD_ISSET(mSock, &read_fds)) {
             struct sockaddr addr;
-            socklen_t alen = sizeof(addr);
+            socklen_t alen;
             int c;
 
-            if ((c = accept(mSock, &addr, &alen)) < 0) {
+            do {
+                alen = sizeof(addr);
+                c = accept(mSock, &addr, &alen);
+            } while (c < 0 && errno == EINTR);
+            if (c < 0) {
                 SLOGE("accept failed (%s)", strerror(errno));
                 sleep(1);
                 continue;
@@ -184,27 +195,42 @@
             pthread_mutex_unlock(&mClientsLock);
         }
 
-        do {
-            pthread_mutex_lock(&mClientsLock);
-            for (it = mClients->begin(); it != mClients->end(); ++it) {
-                int fd = (*it)->getSocket();
-                if (FD_ISSET(fd, &read_fds)) {
-                    pthread_mutex_unlock(&mClientsLock);
-                    if (!onDataAvailable(*it)) {
-                        close(fd);
-                        pthread_mutex_lock(&mClientsLock);
-                        delete *it;
-                        it = mClients->erase(it);
-                        pthread_mutex_unlock(&mClientsLock);
-                    }
-                    FD_CLR(fd, &read_fds);
-                    pthread_mutex_lock(&mClientsLock);
-                    continue;
-                }
+        /* Add all active clients to the pending list first */
+        pendingList->clear();
+        pthread_mutex_lock(&mClientsLock);
+        for (it = mClients->begin(); it != mClients->end(); ++it) {
+            int fd = (*it)->getSocket();
+            if (FD_ISSET(fd, &read_fds)) {
+                pendingList->push_back(*it);
             }
-            pthread_mutex_unlock(&mClientsLock);
-        } while (0);
+        }
+        pthread_mutex_unlock(&mClientsLock);
+
+        /* Process the pending list, since it is owned by the thread,
+         * there is no need to lock it */
+        while (!pendingList->empty()) {
+            /* Pop the first item from the list */
+            it = pendingList->begin();
+            SocketClient* c = *it;
+            pendingList->erase(it);
+            /* Process it, if false is returned, remove and destroy it */
+            if (!onDataAvailable(c)) {
+                /* Remove the client from our array */
+                pthread_mutex_lock(&mClientsLock);
+                for (it = mClients->begin(); it != mClients->end(); ++it) {
+                    if (*it == c) {
+                        mClients->erase(it);
+                        break;
+                    }
+                }
+                pthread_mutex_unlock(&mClientsLock);
+                /* Destroy the client */
+                close(c->getSocket());
+                delete c;
+            }
+        }
     }
+    delete pendingList;
 }
 
 void SocketListener::sendBroadcast(int code, const char *msg, bool addErrno) {
diff --git a/libusbhost/usbhost.c b/libusbhost/usbhost.c
index d6736d3..89a7f0a 100644
--- a/libusbhost/usbhost.c
+++ b/libusbhost/usbhost.c
@@ -60,7 +60,7 @@
 
 struct usb_device {
     char dev_name[64];
-    unsigned char desc[256];
+    unsigned char desc[4096];
     int desc_length;
     int fd;
     int writeable;
@@ -204,6 +204,8 @@
 {
     int fd, did_retry = 0, writeable = 1;
 
+    D("usb_device_open %s\n", dev_name);
+
 retry:
     fd = open(dev_name, O_RDWR);
     if (fd < 0) {
@@ -240,10 +242,12 @@
     struct usb_device *device = calloc(1, sizeof(struct usb_device));
     int length;
 
+    D("usb_device_new %s fd: %d\n", dev_name, fd);
+
     if (lseek(fd, 0, SEEK_SET) != 0)
         goto failed;
     length = read(fd, device->desc, sizeof(device->desc));
-    D("usb_device_new read returned %d errno %d\n", fd, errno);
+    D("usb_device_new read returned %d errno %d\n", length, errno);
     if (length < 0)
         goto failed;
 
@@ -452,6 +456,17 @@
     return ioctl(device->fd, USBDEVFS_RELEASEINTERFACE, &interface);
 }
 
+int usb_device_connect_kernel_driver(struct usb_device *device,
+        unsigned int interface, int connect)
+{
+    struct usbdevfs_ioctl ctl;
+
+    ctl.ifno = interface;
+    ctl.ioctl_code = (connect ? USBDEVFS_CONNECT : USBDEVFS_DISCONNECT);
+    ctl.data = NULL;
+    return ioctl(device->fd, USBDEVFS_IOCTL, &ctl);
+}
+
 struct usb_request *usb_request_new(struct usb_device *dev,
         const struct usb_endpoint_descriptor *ep_desc)
 {
diff --git a/logcat/event.logtags b/logcat/event.logtags
index eee08c6..2e814ff 100644
--- a/logcat/event.logtags
+++ b/logcat/event.logtags
@@ -63,47 +63,7 @@
 # ZygoteInit class preloading ends:
 3030 boot_progress_preload_end (time|2|3)
 
-# dvm_gc_info: LIST (LONG, LONG, LONG)
-#
-# First LONG:
-#
-#    [63]    1
-#    [62-24] ASCII process identifier
-#    [23-12] GC time in ms
-#    [11- 0] Bytes freed
-#
-# Second LONG (aggregated heap info):
-#
-#    [63-62] 10
-#    [61-60] Reserved; must be zero
-#    [59-48] Objects freed
-#    [47-36] Actual size (current footprint)
-#    [35-24] Allowed size (current hard max)
-#    [23-12] Objects allocated
-#    [11- 0] Bytes allocated
-#
-# Third LONG (zygote heap info):
-#
-#    [63-62] 11
-#    [61-60] Reserved; must be zero
-#    [59-48] Soft limit
-#    [47-36] Actual size (current footprint)
-#    [35-24] Allowed size (current hard max)
-#    [23-12] Objects allocated
-#    [11- 0] Bytes allocated
-#
-# Fourth LONG:
-#
-#    [63-48] Reserved; must be zero
-#    [47-36] dlmallocFootprint
-#    [35-24] mallinfo: total allocated space
-#    [23-12] External byte limit
-#    [11- 0] External bytes allocated
-#
-# See HeapDebug.c
-#
-20001 dvm_gc_info (custom|2),(custom|2),(custom|2),(custom|2)
-20002 dvm_gc_madvise_info (total|1|2),(zygote|1|2)
+# Dalvik VM
 20003 dvm_lock_sample (process|3),(main|1|5),(thread|3),(time|1|3),(file|3),(line|1|5),(ownerfile|3),(ownerline|1|5),(sample_percent|1|6)
 
 75000 sqlite_mem_alarm_current (current|1|2)
diff --git a/rootdir/etc/init.goldfish.rc b/rootdir/etc/init.goldfish.rc
index fa70c2e..7cc028f 100644
--- a/rootdir/etc/init.goldfish.rc
+++ b/rootdir/etc/init.goldfish.rc
@@ -6,6 +6,7 @@
 
 on boot
     setprop ARGH ARGH
+    setprop net.eth0.gw 10.0.2.2
     setprop net.eth0.dns1 10.0.2.3
     setprop net.gprs.local-ip 10.0.2.15
     setprop ro.radio.use-ppp no
@@ -27,6 +28,12 @@
     start goldfish-logcat
     start goldfish-setup
 
+    # This is a workaround for another bug in init and init.rc
+    # where the late_start class of services is never started
+    # properly when running an unencrypted /data partition.
+    #
+    start ril-daemon
+
     setprop ro.setupwizard.mode EMULATOR
 
 # enable Google-specific location features,
diff --git a/rootdir/etc/init.goldfish.sh b/rootdir/etc/init.goldfish.sh
index c18c032..1156dd7 100755
--- a/rootdir/etc/init.goldfish.sh
+++ b/rootdir/etc/init.goldfish.sh
@@ -1,8 +1,26 @@
 #!/system/bin/sh
 
+# Setup networking when boot starts
 ifconfig eth0 10.0.2.15 netmask 255.255.255.0 up
 route add default gw 10.0.2.2 dev eth0
 
+# ro.kernel.android.qemud is normally set when we
+# want the RIL (radio interface layer) to talk to
+# the emulated modem through qemud.
+#
+# However, this will be undefined in two cases:
+#
+# - When we want the RIL to talk directly to a guest
+#   serial device that is connected to a host serial
+#   device by the emulator.
+#
+# - We don't want to use the RIL but the VM-based
+#   modem emulation that runs inside the guest system
+#   instead.
+#
+# The following detects the latter case and sets up the
+# system for it.
+#
 qemud=`getprop ro.kernel.android.qemud`
 case "$qemud" in
     "")
@@ -18,17 +36,18 @@
     ;;
 esac
 
+# Setup additionnal DNS servers if needed
 num_dns=`getprop ro.kernel.ndns`
 case "$num_dns" in
     2) setprop net.eth0.dns2 10.0.2.4
-    ;;
+       ;;
     3) setprop net.eth0.dns2 10.0.2.4
-    setprop net.eth0.dns3 10.0.2.5
-    ;;
+       setprop net.eth0.dns3 10.0.2.5
+       ;;
     4) setprop net.eth0.dns2 10.0.2.4
-    setprop net.eth0.dns3 10.0.2.5
-    setprop net.eth0.dns4 10.0.2.6
-    ;;
+       setprop net.eth0.dns3 10.0.2.5
+       setprop net.eth0.dns4 10.0.2.6
+       ;;
 esac
 
 # disable boot animation for a faster boot sequence when needed
@@ -42,10 +61,6 @@
 #
 /system/bin/qemu-props
 
-# this line doesn't really do anything useful. however without it the
-# previous setprop doesn't seem to apply for some really odd reason
-#setprop ro.qemu.init.completed 1
-
 # set up the second interface (for inter-emulator connections)
 # if required
 my_ip=`getprop net.shared_net_ip`
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 9a8ea0f..f6c1162 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -19,7 +19,7 @@
     export ANDROID_DATA /data
     export ASEC_MOUNTPOINT /mnt/asec
     export LOOP_MOUNTPOINT /mnt/obb
-    export BOOTCLASSPATH /system/framework/core.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/android.policy.jar:/system/framework/services.jar:/system/framework/core-junit.jar
+    export BOOTCLASSPATH /system/framework/core.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/android.policy.jar:/system/framework/services.jar:/system/framework/apache-xml.jar:/system/framework/core-junit.jar
 
 # Backward compatibility
     symlink /system/etc /etc
@@ -296,6 +296,9 @@
 on property:vold.decrypt=trigger_post_fs_data
     trigger post-fs-data
 
+on property:vold.decrypt=trigger_restart_min_framework
+    class_start main
+
 on property:vold.decrypt=trigger_restart_framework
     class_start main
     class_start late_start
@@ -357,7 +360,7 @@
     class main
 
 service ril-daemon /system/bin/rild
-    class core
+    class late_start
     socket rild stream 660 root radio
     socket rild-debug stream 660 radio system
     user root
@@ -376,11 +379,6 @@
     user drm
     group inet
 
-service drmio /system/bin/drmioserver
-    class main
-    user drmio
-    group drmio
-
 service media /system/bin/mediaserver
     class main
     user media
diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c
index 21a44ce..9bb9d4b 100644
--- a/sdcard/sdcard.c
+++ b/sdcard/sdcard.c
@@ -95,6 +95,12 @@
     __u32 namelen;
 
     char *name;
+    /* If non-null, this is the real name of the file in the underlying storage.
+     * This may differ from the field "name" only by case.
+     * strlen(actual_name) will always equal strlen(name), so it is safe to use
+     * namelen for both fields.
+     */
+    char *actual_name;
 };
 
 struct fuse {
@@ -109,21 +115,24 @@
     char rootpath[1024];
 };
 
-/* true if file names should be squashed to lower case */
-static int force_lower_case = 0;
 static unsigned uid = -1;
 static unsigned gid = -1;
 
 #define PATH_BUFFER_SIZE 1024
 
+#define NO_CASE_SENSITIVE_MATCH 0
+#define CASE_SENSITIVE_MATCH 1
+
 /*
  * Get the real-life absolute path to a node.
  *   node: start at this node
  *   buf: storage for returned string
  *   name: append this string to path if set
  */
-char *node_get_path(struct node *node, char *buf, const char *name)
+char *do_node_get_path(struct node *node, char *buf, const char *name, int match_case_insensitive)
 {
+    struct node *in_node = node;
+    const char *in_name = name;
     char *out = buf + PATH_BUFFER_SIZE - 1;
     int len;
     out[0] = 0;
@@ -134,7 +143,7 @@
     }
 
     while (node) {
-        name = node->name;
+        name = (node->actual_name ? node->actual_name : node->name);
         len = node->namelen;
         node = node->parent;
     start:
@@ -142,11 +151,45 @@
             return 0;
         out -= len;
         memcpy(out, name, len);
-        out --;
-        out[0] = '/';
+        /* avoid double slash at beginning of path */
+        if (out[0] != '/') {
+            out --;
+            out[0] = '/';
+        }
     }
 
-    return out;
+    /* If we are searching for a file within node (rather than computing node's path)
+     * and fail, then we need to look for a case insensitive match.
+     */
+    if (in_name && match_case_insensitive && access(out, F_OK) != 0) {
+        char *path, buffer[PATH_BUFFER_SIZE];
+        DIR* dir;
+        struct dirent* entry;
+        path = do_node_get_path(in_node, buffer, NULL, NO_CASE_SENSITIVE_MATCH);
+        dir = opendir(path);
+        if (!dir) {
+            ERROR("opendir %s failed: %s", path, strerror(errno));
+            return out;
+        }
+
+        while ((entry = readdir(dir))) {
+            if (!strcasecmp(entry->d_name, in_name)) {
+                /* we have a match - replace the name */
+                len = strlen(in_name);
+                memcpy(buf + PATH_BUFFER_SIZE - len - 1, entry->d_name, len);
+                break;
+            }
+        }
+        closedir(dir);
+    }
+
+   return out;
+}
+
+char *node_get_path(struct node *node, char *buf, const char *name)
+{
+    /* We look for case insensitive matches by default */
+    return do_node_get_path(node, buf, name, CASE_SENSITIVE_MATCH);
 }
 
 void attr_from_stat(struct fuse_attr *attr, struct stat *s)
@@ -204,6 +247,41 @@
     parent->refcount++;
 }
 
+/* Check to see if our parent directory already has a file with a name
+ * that differs only by case.  If we find one, store it in the actual_name
+ * field so node_get_path will map it to this file in the underlying storage.
+ */
+static void node_find_actual_name(struct node *node)
+{
+    char *path, buffer[PATH_BUFFER_SIZE];
+    const char *node_name = node->name;
+    DIR* dir;
+    struct dirent* entry;
+
+    if (!node->parent) return;
+
+    path = node_get_path(node->parent, buffer, 0);
+    dir = opendir(path);
+    if (!dir) {
+        ERROR("opendir %s failed: %s", path, strerror(errno));
+        return;
+    }
+
+    while ((entry = readdir(dir))) {
+        const char *test_name = entry->d_name;
+        if (strcmp(test_name, node_name) && !strcasecmp(test_name, node_name)) {
+            /* we have a match - differs but only by case */
+            node->actual_name = strdup(test_name);
+            if (!node->actual_name) {
+                ERROR("strdup failed - out of memory\n");
+                exit(1);
+            }
+            break;
+        }
+    }
+    closedir(dir);
+}
+
 struct node *node_create(struct node *parent, const char *name, __u64 nid, __u64 gen)
 {
     struct node *node;
@@ -224,7 +302,7 @@
     add_node_to_parent(node, parent);
     memcpy(node->name, name, namelen + 1);
     node->namelen = namelen;
-
+    node_find_actual_name(node);
     return node;
 }
 
@@ -236,6 +314,7 @@
         return 0;
     node->name = newname;
     memcpy(node->name, name, node->namelen + 1);
+    node_find_actual_name(node);
     return node->name;
 }
 
@@ -387,6 +466,7 @@
             /* TODO: remove debugging - poison memory */
         memset(node->name, 0xef, node->namelen);
         free(node->name);
+        free(node->actual_name);
         memset(node, 0xfc, sizeof(*node));
         free(node);
     }
@@ -448,84 +528,6 @@
     fuse_reply(fuse, unique, &out, sizeof(out));
 }
 
-static int name_needs_normalizing(const char* name) {
-    char ch;
-    while ((ch = *name++) != 0) {
-        if (ch != tolower(ch))
-            return 1;
-    }
-    return 0;
-}
-
-static void normalize_name(char *name)
-{
-    if (force_lower_case) {
-        char ch;
-        while ((ch = *name) != 0)
-            *name++ = tolower(ch);
-    }
-}
-
-static void recursive_fix_files(const char* path) {
-    DIR* dir;
-    struct dirent* entry;
-    char pathbuf[PATH_MAX];
-    char oldpath[PATH_MAX];
-    int pathLength = strlen(path);
-    int pathRemaining;
-    char* fileSpot;
-
-    if (pathLength >= sizeof(pathbuf) - 1) {
-        ERROR("path too long: %s\n", path);
-        return;
-    }
-    strcpy(pathbuf, path);
-    if (pathbuf[pathLength - 1] != '/') {
-        pathbuf[pathLength++] = '/';
-    }
-    fileSpot = pathbuf + pathLength;
-    pathRemaining = sizeof(pathbuf) - pathLength - 1;
-
-    dir = opendir(path);
-    if (!dir) {
-        ERROR("opendir %s failed: %s", path, strerror(errno));
-        return;
-    }
-
-    while ((entry = readdir(dir))) {
-        const char* name = entry->d_name;
-        int nameLength;
-
-        // ignore "." and ".."
-        if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
-            continue;
-        }
-
-       nameLength = strlen(name);
-       if (nameLength > pathRemaining) {
-            ERROR("path %s/%s too long\n", path, name);
-            continue;
-        }
-        strcpy(fileSpot, name);
-
-        // make sure owner and group are correct
-        chown(pathbuf, uid, gid);
-
-        if (name_needs_normalizing(name)) {
-            /* rename file to lower case file name */
-            strlcpy(oldpath, pathbuf, sizeof(oldpath));
-            normalize_name(pathbuf);
-            rename(oldpath, pathbuf);
-        }
-
-        if (entry->d_type == DT_DIR) {
-            /* recurse to subdirectories */
-            recursive_fix_files(pathbuf);
-        }
-    }
-    closedir(dir);
-}
-
 void handle_fuse_request(struct fuse *fuse, struct fuse_in_header *hdr, void *data, unsigned len)
 {
     struct node *node;
@@ -549,7 +551,6 @@
 
     switch (hdr->opcode) {
     case FUSE_LOOKUP: { /* bytez[] -> entry_out */
-        normalize_name((char*) data);
         TRACE("LOOKUP %llx %s\n", hdr->nodeid, (char*) data);
         lookup_entry(fuse, node, (char*) data, hdr->unique);
         return;
@@ -609,8 +610,6 @@
         char *name = ((char*) data) + sizeof(*req);
         int res;
 
-        normalize_name(name);
-
         TRACE("MKNOD %s @ %llx\n", name, hdr->nodeid);
         path = node_get_path(node, buffer, name);
 
@@ -630,8 +629,6 @@
         char *name = ((char*) data) + sizeof(*req);
         int res;
 
-        normalize_name(name);
-
         TRACE("MKDIR %s @ %llx 0%o\n", name, hdr->nodeid, req->mode);
         path = node_get_path(node, buffer, name);
 
@@ -647,7 +644,6 @@
     case FUSE_UNLINK: { /* bytez[] -> */
         char *path, buffer[PATH_BUFFER_SIZE];
         int res;
-        normalize_name((char*) data);
         TRACE("UNLINK %s @ %llx\n", (char*) data, hdr->nodeid);
         path = node_get_path(node, buffer, (char*) data);
         res = unlink(path);
@@ -657,7 +653,6 @@
     case FUSE_RMDIR: { /* bytez[] -> */
         char *path, buffer[PATH_BUFFER_SIZE];
         int res;
-        normalize_name((char*) data);
         TRACE("RMDIR %s @ %llx\n", (char*) data, hdr->nodeid);
         path = node_get_path(node, buffer, (char*) data);
         res = rmdir(path);
@@ -674,9 +669,6 @@
         struct node *newparent;
         int res;
 
-        normalize_name(oldname);
-        normalize_name(newname);
-
         TRACE("RENAME %s->%s @ %llx\n", oldname, newname, hdr->nodeid);
 
         target = lookup_child_by_name(node, oldname);
@@ -691,7 +683,16 @@
             fuse_status(fuse, hdr->unique, -ENOENT);
             return;
         }
-        newpath = node_get_path(newparent, newbuffer, newname);
+        if (newparent == node) {
+            /* Special case for renaming a file where destination
+             * is same path differing only by case.
+             * In this case we don't want to look for a case insensitive match.
+             * This allows commands like "mv foo FOO" to work as expected.
+             */
+            newpath = do_node_get_path(newparent, newbuffer, newname, NO_CASE_SENSITIVE_MATCH);
+        } else {
+            newpath = node_get_path(newparent, newbuffer, newname);
+        }
 
         if (!remove_child(node, target->nid)) {
             ERROR("RENAME remove_child not found");
@@ -723,7 +724,6 @@
             return;
         }
 
-        normalize_name(buffer);
         path = node_get_path(node, buffer, 0);
         TRACE("OPEN %llx '%s' 0%o fh=%p\n", hdr->nodeid, path, req->flags, h);
         h->fd = open(path, req->flags);
@@ -825,7 +825,6 @@
             return;
         }
 
-        normalize_name(buffer);
         path = node_get_path(node, buffer, 0);
         TRACE("OPENDIR %llx '%s'\n", hdr->nodeid, path);
         h->d = opendir(path);
@@ -933,30 +932,19 @@
     int fd;
     int res;
     const char *path = NULL;
-    int fix_files = 0;
     int i;
 
     for (i = 1; i < argc; i++) {
         char* arg = argv[i];
-        if (arg[0] == '-') {
-            if (!strcmp(arg, "-l")) {
-                force_lower_case = 1;
-            } else if (!strcmp(arg, "-f")) {
-                fix_files = 1;
-            } else {
-                return usage();
-            }
-        } else {
-            if (!path)
-                path = arg;
-            else if (uid == -1)
-                uid = strtoul(arg, 0, 10);
-            else if (gid == -1)
-                gid = strtoul(arg, 0, 10);
-            else {
-                ERROR("too many arguments\n");
-                return usage();
-            }
+        if (!path)
+            path = arg;
+        else if (uid == -1)
+            uid = strtoul(arg, 0, 10);
+        else if (gid == -1)
+            gid = strtoul(arg, 0, 10);
+        else {
+            ERROR("too many arguments\n");
+            return usage();
         }
     }
 
@@ -987,9 +975,6 @@
         return -1;
     }
 
-    if (fix_files)
-        recursive_fix_files(path);
-
     if (setgid(gid) < 0) {
         ERROR("cannot setgid!\n");
         return -1;
diff --git a/toolbox/r.c b/toolbox/r.c
index 5a82e20..eb8ea0b 100644
--- a/toolbox/r.c
+++ b/toolbox/r.c
@@ -13,8 +13,10 @@
 int r_main(int argc, char *argv[])
 {
     int width = 4, set = 0, fd;
-    unsigned addr, value;
+    unsigned addr, value, endaddr = 0;
+    unsigned long mmap_start, mmap_size;
     void *page;
+    char *end;
     
     if(argc < 2) return usage();
 
@@ -31,6 +33,18 @@
     if(argc < 2) return usage();
     addr = strtoul(argv[1], 0, 16);
 
+    end = strchr(argv[1], '-');
+    if (end)
+        endaddr = strtoul(end + 1, 0, 16);
+
+    if (!endaddr)
+        endaddr = addr + width - 1;
+
+    if (endaddr <= addr) {
+        fprintf(stderr, "invalid end address\n");
+        return -1;
+    }
+
     if(argc > 2) {
         set = 1;
         value = strtoul(argv[2], 0, 16);
@@ -42,33 +56,40 @@
         return -1;
     }
     
-    page = mmap(0, 8192, PROT_READ | PROT_WRITE,
-                MAP_SHARED, fd, addr & (~4095));
+    mmap_start = addr & ~(PAGE_SIZE - 1);
+    mmap_size = endaddr - mmap_start + 1;
+    mmap_size = (mmap_size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
+
+    page = mmap(0, mmap_size, PROT_READ | PROT_WRITE,
+                MAP_SHARED, fd, mmap_start);
 
     if(page == MAP_FAILED){
         fprintf(stderr,"cannot mmap region\n");
         return -1;
     }
 
-    switch(width){
-    case 4: {
-        unsigned *x = (unsigned*) (((unsigned) page) + (addr & 4095));
-        if(set) *x = value;
-        fprintf(stderr,"%08x: %08x\n", addr, *x);
-        break;
+    while (addr <= endaddr) {
+        switch(width){
+        case 4: {
+            unsigned *x = (unsigned*) (((unsigned) page) + (addr & 4095));
+            if(set) *x = value;
+            fprintf(stderr,"%08x: %08x\n", addr, *x);
+            break;
+        }
+        case 2: {
+            unsigned short *x = (unsigned short*) (((unsigned) page) + (addr & 4095));
+            if(set) *x = value;
+            fprintf(stderr,"%08x: %04x\n", addr, *x);
+            break;
+        }
+        case 1: {
+            unsigned char *x = (unsigned char*) (((unsigned) page) + (addr & 4095));
+            if(set) *x = value;
+            fprintf(stderr,"%08x: %02x\n", addr, *x);
+            break;
+        }
+        }
+        addr += width;
     }
-    case 2: {
-        unsigned short *x = (unsigned short*) (((unsigned) page) + (addr & 4095));
-        if(set) *x = value;
-        fprintf(stderr,"%08x: %04x\n", addr, *x);
-        break;
-    }
-    case 1: {
-        unsigned char *x = (unsigned char*) (((unsigned) page) + (addr & 4095));
-        if(set) *x = value;
-        fprintf(stderr,"%08x: %02x\n", addr, *x);
-        break;
-    }
-    }    
     return 0;
 }